@likec4/language-server 1.23.1 → 1.24.1

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 +13 -11
  4. package/dist/ast.d.ts +13 -29
  5. package/dist/ast.js +3 -70
  6. package/dist/bundled.mjs +2441 -2610
  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 +10 -6
  15. package/dist/lsp/CompletionProvider.js +20 -2
  16. package/dist/lsp/DocumentLinkProvider.d.ts +3 -3
  17. package/dist/lsp/DocumentLinkProvider.js +5 -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 +5 -56
  29. package/dist/model/deployments-index.js +61 -137
  30. package/dist/model/fqn-index.d.ts +50 -19
  31. package/dist/model/fqn-index.js +176 -69
  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 +10 -9
  35. package/dist/model/model-builder.js +102 -547
  36. package/dist/model/model-locator.d.ts +2 -1
  37. package/dist/model/model-locator.js +7 -9
  38. package/dist/model/model-parser.d.ts +156 -150
  39. package/dist/model/model-parser.js +68 -38
  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 +23 -20
  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 +12 -13
  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,84 @@
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("ModelBuilder");
464
25
  export class LikeC4ModelBuilder extends ADisposable {
26
+ parser;
27
+ listeners = [];
28
+ cache;
29
+ DocumentBuilder;
30
+ LangiumDocuments;
465
31
  constructor(services) {
466
32
  super();
467
- this.services = services;
468
- this.langiumDocuments = services.shared.workspace.LangiumDocuments;
469
- const parser = services.likec4.ModelParser;
33
+ this.parser = services.likec4.ModelParser;
34
+ this.cache = services.ValidatedWorkspaceCache;
35
+ this.DocumentBuilder = services.shared.workspace.DocumentBuilder;
36
+ this.LangiumDocuments = services.shared.workspace.LangiumDocuments;
470
37
  this.onDispose(
471
- services.shared.workspace.DocumentBuilder.onUpdate((_changed, deleted) => {
38
+ this.DocumentBuilder.onUpdate((_changed, deleted) => {
472
39
  if (deleted.length > 0) {
473
40
  this.notifyListeners(deleted);
474
41
  }
475
42
  })
476
43
  );
477
44
  this.onDispose(
478
- services.shared.workspace.DocumentBuilder.onBuildPhase(
45
+ this.DocumentBuilder.onBuildPhase(
479
46
  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
- }
47
+ (docs, _cancelToken) => {
48
+ this.notifyListeners(docs.map((d) => d.uri));
494
49
  }
495
50
  )
496
51
  );
497
- logger.debug`[ModelBuilder] Created`;
52
+ logger.debug`created`;
498
53
  }
499
- langiumDocuments;
500
- listeners = [];
501
54
  /**
502
55
  * WARNING:
503
56
  * This method is internal and should to be called only when all documents are known to be parsed.
504
57
  * Otherwise, the model may be incomplete.
505
58
  */
506
- unsafeSyncBuildModel() {
59
+ unsafeSyncParseModel() {
507
60
  const docs = this.documents();
508
61
  if (docs.length === 0) {
509
- logger.debug("[ModelBuilder] No documents to build model from");
62
+ logger.debug("no documents to build model from");
510
63
  return null;
511
64
  }
512
- const cache = this.services.WorkspaceCache;
65
+ const cache = this.cache;
513
66
  return cache.get(CACHE_KEY_PARSED_MODEL, () => {
514
- logger.debug`[ModelBuilder] buildModel (${docs.length} docs)`;
515
- return buildModel(this.services, docs);
67
+ logger.debug("unsafeSyncParseModel ({docslength} docs)", { docslength: docs.length });
68
+ return buildModel(docs);
516
69
  });
517
70
  }
518
- async buildModel(cancelToken) {
519
- const cache = this.services.WorkspaceCache;
71
+ async parseModel(cancelToken) {
72
+ const cache = this.cache;
520
73
  const cached = cache.get(CACHE_KEY_PARSED_MODEL);
521
74
  if (cached) {
522
- return cached;
75
+ return await Promise.resolve(cached);
523
76
  }
524
- return await this.services.shared.workspace.WorkspaceLock.read(async () => {
525
- if (cancelToken) {
526
- await interruptAndCheck(cancelToken);
527
- }
528
- return this.unsafeSyncBuildModel();
529
- });
77
+ if (this.LangiumDocuments.all.some((doc) => doc.state < DocumentState.Validated)) {
78
+ logger.debug("parseModel: waiting for documents to be validated");
79
+ await this.DocumentBuilder.waitUntil(DocumentState.Validated, cancelToken);
80
+ }
81
+ return this.unsafeSyncParseModel();
530
82
  }
531
83
  previousViews = {};
532
84
  /**
@@ -534,16 +86,24 @@ export class LikeC4ModelBuilder extends ADisposable {
534
86
  * This method is internal and should to be called only when all documents are known to be parsed.
535
87
  * Otherwise, the model may be incomplete.
536
88
  */
537
- unsafeSyncBuildComputedModel(model) {
538
- const cache = this.services.WorkspaceCache;
539
- const viewsCache = this.services.WorkspaceCache;
89
+ unsafeSyncBuildModel() {
90
+ const cache = this.cache;
91
+ const viewsCache = this.cache;
540
92
  return cache.get(CACHE_KEY_COMPUTED_MODEL, () => {
541
- const computeView = LikeC4Model.makeCompute(model);
93
+ const parsed = this.unsafeSyncParseModel();
94
+ if (!parsed) {
95
+ return LikeC4Model.EMPTY;
96
+ }
97
+ const {
98
+ views: parsedViews,
99
+ ...model
100
+ } = parsed;
101
+ const computeView = LikeC4Model.makeCompute(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,69 @@ 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.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 computeView = LikeC4Model.makeCompute(parsed);
154
+ const result = computeView(view);
155
+ if (!result.isSuccess) {
156
+ logWarnError(result.error);
157
+ return null;
158
+ }
159
+ let computedView = result.view;
160
+ const allElementViews = pipe(
161
+ parsed.views,
162
+ values(),
163
+ filter(isScopedElementView),
164
+ filter((v) => v.id !== viewId),
165
+ groupBy((v) => v.viewOf)
166
+ );
167
+ for (const node of computedView.nodes) {
168
+ if (!node.navigateTo) {
169
+ const viewsOfNode = allElementViews[node.id];
170
+ if (viewsOfNode) {
171
+ node.navigateTo = viewsOfNode[0].id;
617
172
  }
618
173
  }
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
- });
174
+ }
175
+ const previous = this.previousViews[viewId];
176
+ if (previous && eq(computedView, previous)) {
177
+ computedView = previous;
178
+ } else {
179
+ this.previousViews[viewId] = computedView;
180
+ }
181
+ return computedView;
627
182
  });
628
183
  }
629
184
  onModelParsed(callback) {
@@ -636,7 +191,7 @@ export class LikeC4ModelBuilder extends ADisposable {
636
191
  });
637
192
  }
638
193
  documents() {
639
- return this.langiumDocuments.all.filter(isParsedLikeC4LangiumDocument).toArray();
194
+ return this.parser.documents().toArray();
640
195
  }
641
196
  notifyListeners(docs) {
642
197
  for (const listener of this.listeners) {