@likec4/language-server 1.23.1 → 1.24.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 (73) hide show
  1. package/dist/LikeC4FileSystem.d.ts +1 -0
  2. package/dist/LikeC4FileSystem.js +7 -0
  3. package/dist/Rpc.js +10 -7
  4. package/dist/ast.d.ts +13 -29
  5. package/dist/ast.js +3 -70
  6. package/dist/bundled.mjs +2466 -2641
  7. package/dist/generated/ast.d.ts +36 -8
  8. package/dist/generated/ast.js +44 -2
  9. package/dist/generated/grammar.js +1 -1
  10. package/dist/index.d.ts +1 -0
  11. package/dist/index.js +1 -0
  12. package/dist/likec4lib.d.ts +2 -0
  13. package/dist/likec4lib.js +3 -0
  14. package/dist/lsp/CodeLensProvider.js +7 -4
  15. package/dist/lsp/CompletionProvider.js +20 -2
  16. package/dist/lsp/DocumentLinkProvider.d.ts +3 -3
  17. package/dist/lsp/DocumentLinkProvider.js +14 -5
  18. package/dist/lsp/DocumentSymbolProvider.d.ts +1 -1
  19. package/dist/lsp/DocumentSymbolProvider.js +5 -2
  20. package/dist/lsp/HoverProvider.js +20 -7
  21. package/dist/lsp/SemanticTokenProvider.js +18 -1
  22. package/dist/model/builder/MergedExtends.d.ts +12 -0
  23. package/dist/model/builder/MergedExtends.js +67 -0
  24. package/dist/model/builder/MergedSpecification.d.ts +29 -0
  25. package/dist/model/builder/MergedSpecification.js +203 -0
  26. package/dist/model/builder/buildModel.d.ts +3 -0
  27. package/dist/model/builder/buildModel.js +194 -0
  28. package/dist/model/deployments-index.d.ts +6 -56
  29. package/dist/model/deployments-index.js +59 -137
  30. package/dist/model/fqn-index.d.ts +47 -17
  31. package/dist/model/fqn-index.js +155 -68
  32. package/dist/model/index.d.ts +0 -1
  33. package/dist/model/index.js +0 -1
  34. package/dist/model/model-builder.d.ts +13 -9
  35. package/dist/model/model-builder.js +101 -547
  36. package/dist/model/model-locator.d.ts +1 -0
  37. package/dist/model/model-locator.js +7 -9
  38. package/dist/model/model-parser.d.ts +24 -18
  39. package/dist/model/model-parser.js +51 -31
  40. package/dist/model/parser/Base.d.ts +3 -3
  41. package/dist/model/parser/Base.js +15 -9
  42. package/dist/model/parser/DeploymentModelParser.d.ts +4 -3
  43. package/dist/model/parser/DeploymentModelParser.js +54 -3
  44. package/dist/model/parser/DeploymentViewParser.d.ts +3 -2
  45. package/dist/model/parser/FqnRefParser.d.ts +2 -2
  46. package/dist/model/parser/GlobalsParser.d.ts +3 -2
  47. package/dist/model/parser/ModelParser.d.ts +4 -4
  48. package/dist/model/parser/ModelParser.js +45 -4
  49. package/dist/model/parser/PredicatesParser.d.ts +2 -2
  50. package/dist/model/parser/SpecificationParser.d.ts +2 -2
  51. package/dist/model/parser/ViewsParser.d.ts +3 -2
  52. package/dist/module.d.ts +2 -3
  53. package/dist/module.js +2 -3
  54. package/dist/references/scope-computation.d.ts +1 -1
  55. package/dist/references/scope-computation.js +14 -11
  56. package/dist/references/scope-provider.d.ts +16 -4
  57. package/dist/references/scope-provider.js +64 -30
  58. package/dist/test/testServices.d.ts +2 -1
  59. package/dist/test/testServices.js +17 -14
  60. package/dist/utils/elementRef.d.ts +1 -1
  61. package/dist/utils/elementRef.js +3 -3
  62. package/dist/validation/deployment-checks.d.ts +1 -0
  63. package/dist/validation/deployment-checks.js +12 -0
  64. package/dist/validation/index.d.ts +1 -1
  65. package/dist/validation/index.js +8 -1
  66. package/dist/views/configurable-layouter.js +3 -3
  67. package/dist/views/likec4-views.d.ts +1 -0
  68. package/dist/views/likec4-views.js +11 -11
  69. package/package.json +6 -7
  70. package/dist/bundled.d.ts +0 -8
  71. package/dist/bundled.js +0 -25
  72. package/dist/model/fqn-computation.d.ts +0 -3
  73. package/dist/model/fqn-computation.js +0 -72
@@ -1,532 +1,82 @@
1
1
  import {
2
- compareRelations,
3
- computeColorValues,
4
- DeploymentElement,
5
2
  isScopedElementView,
6
- LikeC4Model,
7
- parentFqn,
8
- sortByFqnHierarchically
3
+ LikeC4Model
9
4
  } from "@likec4/core";
10
- import { resolveRulesExtendedViews } from "@likec4/core/compute-view";
5
+ import { loggable } from "@likec4/log";
11
6
  import { deepEqual as eq } from "fast-equals";
12
- import { Disposable, DocumentState, interruptAndCheck } from "langium";
7
+ import {
8
+ Disposable,
9
+ DocumentState
10
+ } from "langium";
13
11
  import {
14
12
  filter,
15
- flatMap,
16
13
  groupBy,
17
- hasAtLeast,
18
- indexBy,
19
- isBoolean,
20
- isDefined,
21
- isEmpty,
22
- isNonNullish,
23
- isNullish,
24
- isNumber,
25
- isTruthy,
26
- map,
27
14
  mapToObj,
28
- mapValues,
29
- omit,
30
15
  pipe,
31
- prop,
32
- reduce,
33
- reverse,
34
- sort,
35
- unique,
36
16
  values
37
17
  } from "remeda";
38
- import { isParsedLikeC4LangiumDocument } from "../ast.js";
39
- import { logger, logWarnError } from "../logger.js";
18
+ import { logger as mainLogger, logWarnError } from "../logger.js";
40
19
  import { ADisposable } from "../utils/index.js";
41
- import { assignNavigateTo, resolveRelativePaths } from "../view-utils/index.js";
42
- function buildModel(services, docs) {
43
- const c4Specification = {
44
- tags: /* @__PURE__ */ new Set(),
45
- deployments: {},
46
- elements: {},
47
- relationships: {},
48
- colors: {}
49
- };
50
- const globals = {
51
- predicates: {},
52
- dynamicPredicates: {},
53
- styles: {}
54
- };
55
- for (const doc of docs) {
56
- const {
57
- c4Specification: spec,
58
- c4Globals
59
- } = doc;
60
- spec.tags.forEach((t) => c4Specification.tags.add(t));
61
- Object.assign(c4Specification.elements, spec.elements);
62
- Object.assign(c4Specification.relationships, spec.relationships);
63
- Object.assign(c4Specification.colors, spec.colors);
64
- Object.assign(c4Specification.deployments, spec.deployments);
65
- Object.assign(globals.predicates, c4Globals.predicates);
66
- Object.assign(globals.dynamicPredicates, c4Globals.dynamicPredicates);
67
- Object.assign(globals.styles, c4Globals.styles);
68
- }
69
- function resolveLinks(doc, links) {
70
- return map(
71
- links,
72
- (link) => {
73
- try {
74
- const relative = services.lsp.DocumentLinkProvider.relativeLink(doc, link.url);
75
- if (relative && relative !== link.url) {
76
- return {
77
- ...link,
78
- relative
79
- };
80
- }
81
- } catch (e) {
82
- logWarnError(e);
83
- }
84
- return link;
85
- }
86
- );
87
- }
88
- const customColorDefinitions = mapValues(
89
- c4Specification.colors,
90
- (c) => computeColorValues(c.color)
91
- );
92
- function toModelElement(doc) {
93
- return ({
94
- tags,
95
- links: unresolvedLinks,
96
- style: {
97
- color,
98
- shape,
99
- icon,
100
- opacity,
101
- border,
102
- size,
103
- multiple,
104
- padding,
105
- textSize
106
- },
107
- id,
108
- kind,
109
- title,
110
- description,
111
- technology,
112
- metadata
113
- }) => {
114
- try {
115
- const __kind = c4Specification.elements[kind];
116
- if (!__kind) {
117
- logger.warn`No kind '${kind}' found for ${id}`;
118
- return null;
119
- }
120
- const links = unresolvedLinks ? resolveLinks(doc, unresolvedLinks) : null;
121
- color ??= __kind.style.color;
122
- shape ??= __kind.style.shape;
123
- icon ??= __kind.style.icon;
124
- opacity ??= __kind.style.opacity;
125
- border ??= __kind.style.border;
126
- technology ??= __kind.technology;
127
- multiple ??= __kind.style.multiple;
128
- size ??= __kind.style.size;
129
- padding ??= __kind.style.padding;
130
- textSize ??= __kind.style.textSize;
131
- return {
132
- ...color && { color },
133
- ...shape && { shape },
134
- ...icon && { icon },
135
- ...metadata && !isEmpty(metadata) && { metadata },
136
- ...__kind.notation && { notation: __kind.notation },
137
- style: {
138
- ...border && { border },
139
- ...size && { size },
140
- ...padding && { padding },
141
- ...textSize && { textSize },
142
- ...isBoolean(multiple) && { multiple },
143
- ...isNumber(opacity) && { opacity }
144
- },
145
- links,
146
- tags: tags ?? null,
147
- technology: technology ?? null,
148
- description: description ?? null,
149
- title,
150
- kind,
151
- id
152
- };
153
- } catch (e) {
154
- logWarnError(e);
155
- }
156
- return null;
157
- };
158
- }
159
- const elementsExtendData = /* @__PURE__ */ new Map();
160
- function mergeAllC4ExtendElements(doc) {
161
- for (const el of doc.c4ExtendElements) {
162
- let links = el.links ? resolveLinks(doc, el.links) : null;
163
- const existing = elementsExtendData.get(el.id);
164
- if (existing) {
165
- links = existing.links ? [...existing.links, ...links ?? []] : links;
166
- let tags = [...existing.tags ?? [], ...el.tags ?? []];
167
- if (!hasAtLeast(tags, 1)) {
168
- tags = null;
169
- }
170
- elementsExtendData.set(el.id, {
171
- tags,
172
- links,
173
- metadata: { ...existing.metadata, ...el.metadata }
174
- });
175
- } else {
176
- elementsExtendData.set(el.id, {
177
- tags: el.tags ?? null,
178
- links,
179
- metadata: { ...el.metadata }
180
- });
181
- }
182
- }
183
- }
184
- function withExtendElementData(el) {
185
- const extendData = elementsExtendData.get(el.id);
186
- if (extendData) {
187
- const links = [...el.links ?? [], ...extendData.links ?? []];
188
- const tags = unique([...el.tags ?? [], ...extendData.tags ?? []]);
189
- const metadata = { ...el.metadata, ...extendData.metadata };
190
- return {
191
- ...el,
192
- tags: hasAtLeast(tags, 1) ? tags : null,
193
- links: hasAtLeast(links, 1) ? links : null,
194
- ...!isEmpty(metadata) && { metadata }
195
- };
196
- }
197
- return el;
198
- }
199
- const elements = pipe(
200
- docs,
201
- flatMap((d) => {
202
- mergeAllC4ExtendElements(d);
203
- return map(d.c4Elements, toModelElement(d));
204
- }),
205
- filter(isTruthy),
206
- // sort from root elements to nested, so that parent is always present
207
- // Import to preserve the order from the source
208
- sortByFqnHierarchically,
209
- reduce(
210
- (acc, el) => {
211
- const parent = parentFqn(el.id);
212
- if (parent && isNullish(acc[parent])) {
213
- logger.debug`No parent found for ${el.id}`;
214
- return acc;
215
- }
216
- acc[el.id] = withExtendElementData(el);
217
- return acc;
218
- },
219
- {}
220
- )
221
- );
222
- function toModelRelation(doc) {
223
- return ({
224
- astPath,
225
- source,
226
- target,
227
- kind,
228
- links: unresolvedLinks,
229
- id,
230
- ...model
231
- }) => {
232
- if (isNullish(elements[source]) || isNullish(elements[target])) {
233
- logger.debug`Invalid relation ${id}
234
- source: ${source} resolved: ${!!elements[source]}
235
- target: ${target} resolved: ${!!elements[target]}
236
- at ${doc.uri.path}\n`;
237
- return null;
238
- }
239
- const links = unresolvedLinks ? resolveLinks(doc, unresolvedLinks) : null;
240
- if (isNonNullish(kind) && kind in c4Specification.relationships) {
241
- return {
242
- ...c4Specification.relationships[kind],
243
- ...model,
244
- ...links && { links },
245
- source,
246
- target,
247
- kind,
248
- id
249
- };
250
- }
251
- return {
252
- ...links && { links },
253
- ...model,
254
- source,
255
- target,
256
- id
257
- };
258
- };
259
- }
260
- const relations = pipe(
261
- docs,
262
- flatMap((d) => map(d.c4Relations, toModelRelation(d))),
263
- filter(isTruthy),
264
- sort(compareRelations),
265
- reverse(),
266
- indexBy(prop("id"))
267
- );
268
- function toDeploymentElement(doc) {
269
- return (parsed) => {
270
- if (!DeploymentElement.isDeploymentNode(parsed)) {
271
- if (!parsed.links || parsed.links.length === 0) {
272
- return parsed;
273
- }
274
- const links = resolveLinks(doc, parsed.links);
275
- return {
276
- ...parsed,
277
- links
278
- };
279
- }
280
- try {
281
- const __kind = c4Specification.deployments[parsed.kind];
282
- if (!__kind) {
283
- logger.warn`No kind ${parsed.kind} found for ${parsed.id}`;
284
- return null;
285
- }
286
- let {
287
- technology = __kind.technology,
288
- notation = __kind.notation,
289
- links,
290
- style
291
- } = parsed;
292
- return {
293
- ...parsed,
294
- ...notation && { notation },
295
- ...technology && { technology },
296
- style: {
297
- border: "dashed",
298
- opacity: 10,
299
- ...__kind.style,
300
- ...style
301
- },
302
- links: links ? resolveLinks(doc, links) : null
303
- };
304
- } catch (e) {
305
- logWarnError(e);
306
- }
307
- return null;
308
- };
309
- }
310
- const deploymentElements = pipe(
311
- docs,
312
- flatMap((d) => map(d.c4Deployments, toDeploymentElement(d))),
313
- filter(isTruthy),
314
- // sort from root elements to nested, so that parent is always present
315
- // Import to preserve the order from the source
316
- sortByFqnHierarchically,
317
- reduce(
318
- (acc, el) => {
319
- const parent = parentFqn(el.id);
320
- if (parent && isNullish(acc[parent])) {
321
- logger.debug`No parent found for deployment element ${el.id}`;
322
- return acc;
323
- }
324
- acc[el.id] = el;
325
- return acc;
326
- },
327
- {}
328
- )
329
- );
330
- function toDeploymentRelation(doc) {
331
- return ({
332
- astPath,
333
- source,
334
- target,
335
- kind,
336
- links: unresolvedLinks,
337
- id,
338
- ...model
339
- }) => {
340
- if (isNullish(deploymentElements[source.id]) || isNullish(deploymentElements[target.id])) {
341
- logger.warn`Invalid deployment relation ${id} at ${doc.uri.path} ${astPath}, source: ${source.id}(${!!deploymentElements[source.id]}), target: ${target.id}(${!!deploymentElements[target.id]})`;
342
- return null;
343
- }
344
- const links = unresolvedLinks ? resolveLinks(doc, unresolvedLinks) : null;
345
- if (isNonNullish(kind) && kind in c4Specification.relationships) {
346
- return {
347
- ...c4Specification.relationships[kind],
348
- ...model,
349
- ...links && { links },
350
- source,
351
- target,
352
- kind,
353
- id
354
- };
355
- }
356
- return {
357
- ...links && { links },
358
- ...model,
359
- source,
360
- target,
361
- id
362
- };
363
- };
364
- }
365
- const deploymentRelations = pipe(
366
- docs,
367
- flatMap((d) => map(d.c4DeploymentRelations, toDeploymentRelation(d))),
368
- filter(isTruthy),
369
- reduce(
370
- (acc, el) => {
371
- if (isDefined(acc[el.id])) {
372
- logger.debug`Duplicate deployment relation ${el.id}`;
373
- return acc;
374
- }
375
- acc[el.id] = el;
376
- return acc;
377
- },
378
- {}
379
- )
380
- );
381
- function toC4View(doc) {
382
- const docUri = doc.uri.toString();
383
- return (parsedAstView) => {
384
- let {
385
- id,
386
- title,
387
- description,
388
- tags,
389
- links: unresolvedLinks,
390
- // ignore this property
391
- astPath: _ignore,
392
- // model should include discriminant __
393
- ...model
394
- } = parsedAstView;
395
- if (parsedAstView.__ === "element" && isNullish(title) && "viewOf" in parsedAstView) {
396
- title = elements[parsedAstView.viewOf]?.title ?? null;
397
- }
398
- if (isNullish(title) && id === "index") {
399
- title = "Landscape view";
400
- }
401
- const links = unresolvedLinks ? resolveLinks(doc, unresolvedLinks) : null;
402
- return {
403
- ...model,
404
- customColorDefinitions,
405
- tags,
406
- links,
407
- docUri,
408
- description,
409
- title,
410
- id
411
- };
412
- };
413
- }
414
- const parsedViews = pipe(
415
- docs,
416
- flatMap((d) => map(d.c4Views, toC4View(d))),
417
- // Resolve relative paths and sort by
418
- resolveRelativePaths
419
- );
420
- if (!parsedViews.some((v) => v.id === "index")) {
421
- parsedViews.unshift({
422
- __: "element",
423
- id: "index",
424
- title: "Landscape view",
425
- description: null,
426
- tags: null,
427
- links: null,
428
- customColorDefinitions,
429
- rules: [
430
- {
431
- include: [
432
- {
433
- wildcard: true
434
- }
435
- ]
436
- }
437
- ]
438
- });
439
- }
440
- const views = pipe(
441
- parsedViews,
442
- indexBy(prop("id")),
443
- resolveRulesExtendedViews
444
- );
445
- return {
446
- specification: {
447
- tags: Array.from(c4Specification.tags),
448
- elements: c4Specification.elements,
449
- relationships: c4Specification.relationships,
450
- deployments: c4Specification.deployments
451
- },
452
- elements,
453
- relations,
454
- globals,
455
- views,
456
- deployments: {
457
- elements: deploymentElements,
458
- relations: deploymentRelations
459
- }
460
- };
461
- }
20
+ import { assignNavigateTo } from "../view-utils/index.js";
21
+ import { buildModel } from "./builder/buildModel.js";
462
22
  const CACHE_KEY_PARSED_MODEL = "ParsedLikeC4Model";
463
23
  const CACHE_KEY_COMPUTED_MODEL = "ComputedLikeC4Model";
24
+ const logger = mainLogger.getChild("model-builder");
464
25
  export class LikeC4ModelBuilder extends ADisposable {
26
+ parser;
27
+ listeners = [];
28
+ cache;
29
+ DocumentBuilder;
465
30
  constructor(services) {
466
31
  super();
467
- this.services = services;
468
- this.langiumDocuments = services.shared.workspace.LangiumDocuments;
469
- const parser = services.likec4.ModelParser;
32
+ this.parser = services.likec4.ModelParser;
33
+ this.cache = services.ValidatedWorkspaceCache;
34
+ this.DocumentBuilder = services.shared.workspace.DocumentBuilder;
470
35
  this.onDispose(
471
- services.shared.workspace.DocumentBuilder.onUpdate((_changed, deleted) => {
36
+ this.DocumentBuilder.onUpdate((_changed, deleted) => {
472
37
  if (deleted.length > 0) {
473
38
  this.notifyListeners(deleted);
474
39
  }
475
40
  })
476
41
  );
477
42
  this.onDispose(
478
- services.shared.workspace.DocumentBuilder.onBuildPhase(
43
+ this.DocumentBuilder.onBuildPhase(
479
44
  DocumentState.Validated,
480
- async (docs, _cancelToken) => {
481
- let parsed = [];
482
- logger.debug`[ModelBuilder] onValidated (${docs.length} docs)`;
483
- for (const doc of docs) {
484
- try {
485
- parsed.push(parser.parse(doc).uri);
486
- } catch (e) {
487
- logWarnError(e);
488
- }
489
- }
490
- await interruptAndCheck(_cancelToken);
491
- if (parsed.length > 0) {
492
- this.notifyListeners(parsed);
493
- }
45
+ (docs, _cancelToken) => {
46
+ logger.debug("onValidated ({docslength} docs)", { docslength: docs.length });
47
+ this.notifyListeners(docs.map((d) => d.uri));
494
48
  }
495
49
  )
496
50
  );
497
- logger.debug`[ModelBuilder] Created`;
51
+ logger.debug`created`;
498
52
  }
499
- langiumDocuments;
500
- listeners = [];
501
53
  /**
502
54
  * WARNING:
503
55
  * This method is internal and should to be called only when all documents are known to be parsed.
504
56
  * Otherwise, the model may be incomplete.
505
57
  */
506
- unsafeSyncBuildModel() {
58
+ unsafeSyncParseModel() {
507
59
  const docs = this.documents();
508
60
  if (docs.length === 0) {
509
- logger.debug("[ModelBuilder] No documents to build model from");
61
+ logger.debug("no documents to build model from");
510
62
  return null;
511
63
  }
512
- const cache = this.services.WorkspaceCache;
64
+ const cache = this.cache;
513
65
  return cache.get(CACHE_KEY_PARSED_MODEL, () => {
514
- logger.debug`[ModelBuilder] buildModel (${docs.length} docs)`;
515
- return buildModel(this.services, docs);
66
+ logger.debug("unsafeSyncParseModel ({docslength} docs)", { docslength: docs.length });
67
+ const model = buildModel(docs);
68
+ const computeView = LikeC4Model.makeCompute(model);
69
+ return { model, computeView };
516
70
  });
517
71
  }
518
- async buildModel(cancelToken) {
519
- const cache = this.services.WorkspaceCache;
72
+ async parseModel(cancelToken) {
73
+ const cache = this.cache;
520
74
  const cached = cache.get(CACHE_KEY_PARSED_MODEL);
521
75
  if (cached) {
522
- return cached;
76
+ return await Promise.resolve(cached);
523
77
  }
524
- return await this.services.shared.workspace.WorkspaceLock.read(async () => {
525
- if (cancelToken) {
526
- await interruptAndCheck(cancelToken);
527
- }
528
- return this.unsafeSyncBuildModel();
529
- });
78
+ await this.DocumentBuilder.waitUntil(DocumentState.Validated, cancelToken);
79
+ return this.unsafeSyncParseModel();
530
80
  }
531
81
  previousViews = {};
532
82
  /**
@@ -534,16 +84,26 @@ export class LikeC4ModelBuilder extends ADisposable {
534
84
  * This method is internal and should to be called only when all documents are known to be parsed.
535
85
  * Otherwise, the model may be incomplete.
536
86
  */
537
- unsafeSyncBuildComputedModel(model) {
538
- const cache = this.services.WorkspaceCache;
539
- const viewsCache = this.services.WorkspaceCache;
87
+ unsafeSyncBuildModel() {
88
+ const parsed = this.unsafeSyncParseModel();
89
+ if (!parsed) {
90
+ return LikeC4Model.EMPTY;
91
+ }
92
+ const cache = this.cache;
93
+ const viewsCache = this.cache;
540
94
  return cache.get(CACHE_KEY_COMPUTED_MODEL, () => {
541
- const computeView = LikeC4Model.makeCompute(model);
95
+ const {
96
+ model: {
97
+ views: parsedViews,
98
+ ...model
99
+ },
100
+ computeView
101
+ } = parsed;
542
102
  const allViews = [];
543
- for (const view of values(model.views)) {
103
+ for (const view of values(parsedViews)) {
544
104
  const result = computeView(view);
545
105
  if (!result.isSuccess) {
546
- logWarnError(result.error);
106
+ logger.warn(loggable(result.error));
547
107
  continue;
548
108
  }
549
109
  allViews.push(result.view);
@@ -556,74 +116,68 @@ export class LikeC4ModelBuilder extends ADisposable {
556
116
  return [v.id, view];
557
117
  });
558
118
  this.previousViews = { ...views };
559
- return {
560
- ...omit(model, ["views"]),
119
+ return LikeC4Model.create({
120
+ ...model,
561
121
  views
562
- };
122
+ });
563
123
  });
564
124
  }
565
- async buildComputedModel(cancelToken) {
566
- const cache = this.services.WorkspaceCache;
567
- if (cache.has(CACHE_KEY_COMPUTED_MODEL)) {
568
- return cache.get(CACHE_KEY_COMPUTED_MODEL);
125
+ async buildLikeC4Model(cancelToken) {
126
+ const cache = this.cache;
127
+ const cached = cache.get(CACHE_KEY_COMPUTED_MODEL);
128
+ if (cached) {
129
+ return await Promise.resolve(cached);
569
130
  }
570
- return await this.services.shared.workspace.WorkspaceLock.read(async () => {
571
- if (cancelToken) {
572
- await interruptAndCheck(cancelToken);
573
- }
574
- const model = this.unsafeSyncBuildModel();
575
- if (!model) {
576
- return null;
577
- }
578
- return this.unsafeSyncBuildComputedModel(model);
579
- });
131
+ const model = await this.parseModel(cancelToken);
132
+ if (!model) {
133
+ return LikeC4Model.EMPTY;
134
+ }
135
+ return this.unsafeSyncBuildModel();
580
136
  }
581
137
  async computeView(viewId, cancelToken) {
582
- const cache = this.services.WorkspaceCache;
138
+ const cache = this.cache;
583
139
  const cacheKey = computedViewKey(viewId);
584
140
  if (cache.has(cacheKey)) {
585
141
  return cache.get(cacheKey);
586
142
  }
587
- return await this.services.shared.workspace.WorkspaceLock.read(async () => {
588
- if (cancelToken) {
589
- await interruptAndCheck(cancelToken);
143
+ const parsed = await this.parseModel(cancelToken);
144
+ if (!parsed) {
145
+ return null;
146
+ }
147
+ return cache.get(cacheKey, () => {
148
+ const view = parsed.model.views[viewId];
149
+ if (!view) {
150
+ logger.warn(`[ModelBuilder] Cannot find view ${viewId}`);
151
+ return null;
590
152
  }
591
- return cache.get(cacheKey, () => {
592
- const model = this.unsafeSyncBuildModel();
593
- const view = model?.views[viewId];
594
- if (!view) {
595
- logger.warn(`[ModelBuilder] Cannot find view ${viewId}`);
596
- return null;
597
- }
598
- const result = LikeC4Model.makeCompute(model)(view);
599
- if (!result.isSuccess) {
600
- logWarnError(result.error);
601
- return null;
602
- }
603
- let computedView = result.view;
604
- const allElementViews = pipe(
605
- model.views,
606
- values(),
607
- filter(isScopedElementView),
608
- filter((v) => v.id !== viewId),
609
- groupBy((v) => v.viewOf)
610
- );
611
- for (const node of computedView.nodes) {
612
- if (!node.navigateTo) {
613
- const viewsOfNode = allElementViews[node.id];
614
- if (viewsOfNode) {
615
- node.navigateTo = viewsOfNode[0].id;
616
- }
153
+ const result = parsed.computeView(view);
154
+ if (!result.isSuccess) {
155
+ logWarnError(result.error);
156
+ return null;
157
+ }
158
+ let computedView = result.view;
159
+ const allElementViews = pipe(
160
+ parsed.model.views,
161
+ values(),
162
+ filter(isScopedElementView),
163
+ filter((v) => v.id !== viewId),
164
+ groupBy((v) => v.viewOf)
165
+ );
166
+ for (const node of computedView.nodes) {
167
+ if (!node.navigateTo) {
168
+ const viewsOfNode = allElementViews[node.id];
169
+ if (viewsOfNode) {
170
+ node.navigateTo = viewsOfNode[0].id;
617
171
  }
618
172
  }
619
- const previous = this.previousViews[viewId];
620
- if (previous && eq(computedView, previous)) {
621
- computedView = previous;
622
- } else {
623
- this.previousViews[viewId] = computedView;
624
- }
625
- return computedView;
626
- });
173
+ }
174
+ const previous = this.previousViews[viewId];
175
+ if (previous && eq(computedView, previous)) {
176
+ computedView = previous;
177
+ } else {
178
+ this.previousViews[viewId] = computedView;
179
+ }
180
+ return computedView;
627
181
  });
628
182
  }
629
183
  onModelParsed(callback) {
@@ -636,7 +190,7 @@ export class LikeC4ModelBuilder extends ADisposable {
636
190
  });
637
191
  }
638
192
  documents() {
639
- return this.langiumDocuments.all.filter(isParsedLikeC4LangiumDocument).toArray();
193
+ return this.parser.documents().toArray();
640
194
  }
641
195
  notifyListeners(docs) {
642
196
  for (const listener of this.listeners) {