@likec4/language-server 1.40.0 → 1.42.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 (94) hide show
  1. package/browser/package.json +4 -0
  2. package/browser-worker/package.json +4 -0
  3. package/dist/LikeC4LanguageServices.d.ts +1 -1
  4. package/dist/LikeC4LanguageServices.mjs +3 -2
  5. package/dist/Rpc.mjs +30 -24
  6. package/dist/ast.d.ts +4 -9
  7. package/dist/ast.mjs +0 -10
  8. package/dist/bundled.mjs +4158 -3687
  9. package/dist/documentation/documentation-provider.mjs +1 -1
  10. package/dist/filesystem/FileSystemWatcher.d.ts +2 -2
  11. package/dist/filesystem/index.d.ts +1 -1
  12. package/dist/formatting/LikeC4Formatter.mjs +42 -10
  13. package/dist/formatting/utils.d.ts +3 -3
  14. package/dist/formatting/utils.mjs +1 -1
  15. package/dist/generated/ast.d.ts +40 -19
  16. package/dist/generated/ast.mjs +71 -26
  17. package/dist/generated/grammar.mjs +1 -1
  18. package/dist/logger.d.ts +1 -1
  19. package/dist/logger.mjs +3 -0
  20. package/dist/lsp/CompletionProvider.mjs +1 -1
  21. package/dist/lsp/DocumentLinkProvider.d.ts +1 -1
  22. package/dist/lsp/DocumentLinkProvider.mjs +1 -1
  23. package/dist/lsp/DocumentSymbolProvider.mjs +1 -1
  24. package/dist/lsp/HoverProvider.mjs +14 -2
  25. package/dist/mcp/NoopLikeC4MCPServer.d.ts +1 -1
  26. package/dist/mcp/NoopLikeC4MCPServer.mjs +1 -1
  27. package/dist/mcp/server/StdioLikeC4MCPServer.mjs +4 -1
  28. package/dist/mcp/server/StreamableLikeC4MCPServer.mjs +3 -3
  29. package/dist/mcp/server/WithMCPServer.mjs +2 -2
  30. package/dist/mcp/tools/_common.mjs +2 -2
  31. package/dist/model/builder/MergedSpecification.d.ts +3 -3
  32. package/dist/model/builder/MergedSpecification.mjs +37 -59
  33. package/dist/model/builder/buildModel.mjs +14 -17
  34. package/dist/model/model-builder.d.ts +1 -1
  35. package/dist/model/model-builder.mjs +12 -9
  36. package/dist/model/model-locator.d.ts +5 -0
  37. package/dist/model/model-locator.mjs +40 -3
  38. package/dist/model/model-parser-where.mjs +1 -2
  39. package/dist/model/model-parser.d.ts +91 -47
  40. package/dist/model/parser/Base.d.ts +13 -7
  41. package/dist/model/parser/Base.mjs +32 -21
  42. package/dist/model/parser/DeploymentModelParser.d.ts +9 -5
  43. package/dist/model/parser/DeploymentModelParser.mjs +49 -47
  44. package/dist/model/parser/DeploymentViewParser.d.ts +9 -5
  45. package/dist/model/parser/DeploymentViewParser.mjs +1 -2
  46. package/dist/model/parser/FqnRefParser.d.ts +12 -6
  47. package/dist/model/parser/FqnRefParser.mjs +28 -15
  48. package/dist/model/parser/GlobalsParser.d.ts +16 -7
  49. package/dist/model/parser/GlobalsParser.mjs +5 -3
  50. package/dist/model/parser/ImportsParser.d.ts +8 -5
  51. package/dist/model/parser/ImportsParser.mjs +4 -2
  52. package/dist/model/parser/ModelParser.d.ts +9 -5
  53. package/dist/model/parser/ModelParser.mjs +42 -42
  54. package/dist/model/parser/PredicatesParser.d.ts +9 -5
  55. package/dist/model/parser/SpecificationParser.d.ts +8 -5
  56. package/dist/model/parser/SpecificationParser.mjs +17 -23
  57. package/dist/model/parser/ValueConverter.mjs +1 -1
  58. package/dist/model/parser/ViewsParser.d.ts +20 -7
  59. package/dist/model/parser/ViewsParser.mjs +125 -35
  60. package/dist/model-change/ModelChanges.d.ts +1 -1
  61. package/dist/module.mjs +3 -2
  62. package/dist/protocol.d.ts +28 -4
  63. package/dist/references/scope-computation.mjs +2 -3
  64. package/dist/references/scope-provider.d.ts +2 -2
  65. package/dist/references/scope-provider.mjs +8 -15
  66. package/dist/test/testServices.d.ts +2 -0
  67. package/dist/test/testServices.mjs +32 -35
  68. package/dist/utils/disposable.mjs +2 -2
  69. package/dist/utils/index.mjs +1 -1
  70. package/dist/validation/_shared.d.ts +1 -1
  71. package/dist/validation/deployment-checks.d.ts +1 -1
  72. package/dist/validation/deployment-checks.mjs +4 -1
  73. package/dist/validation/dynamic-view.d.ts +3 -2
  74. package/dist/validation/dynamic-view.mjs +21 -2
  75. package/dist/validation/element-ref.d.ts +2 -2
  76. package/dist/validation/element-ref.mjs +1 -1
  77. package/dist/validation/imports.d.ts +0 -1
  78. package/dist/validation/imports.mjs +0 -5
  79. package/dist/validation/index.d.ts +1 -1
  80. package/dist/validation/index.mjs +19 -13
  81. package/dist/validation/view-predicates/relation-with.d.ts +1 -1
  82. package/dist/validation/view.d.ts +1 -1
  83. package/dist/view-utils/index.d.ts +0 -1
  84. package/dist/view-utils/index.mjs +0 -1
  85. package/dist/views/likec4-views.d.ts +6 -0
  86. package/dist/views/likec4-views.mjs +31 -18
  87. package/dist/workspace/ProjectsManager.d.ts +23 -31
  88. package/dist/workspace/ProjectsManager.mjs +78 -89
  89. package/dist/workspace/WorkspaceManager.mjs +1 -1
  90. package/likec4lib/package.json +4 -0
  91. package/package.json +25 -29
  92. package/protocol/package.json +4 -0
  93. package/dist/view-utils/resolve-relative-paths.d.ts +0 -2
  94. package/dist/view-utils/resolve-relative-paths.mjs +0 -78
@@ -1,9 +1,12 @@
1
1
  import * as c4 from "@likec4/core";
2
+ import { exact } from "@likec4/core";
2
3
  import { nonNullable } from "@likec4/core/utils";
4
+ import { loggable } from "@likec4/log";
3
5
  import { filter, isNonNullish, isNullish, isTruthy, mapToObj, omitBy, pipe } from "remeda";
4
- import { ast, parseMarkdownAsString, toRelationshipStyleExcludeDefaults } from "../../ast.mjs";
5
- import { logger, logWarnError } from "../../logger.mjs";
6
+ import { ast, parseMarkdownAsString, toRelationshipStyle } from "../../ast.mjs";
7
+ import { serverLogger } from "../../logger.mjs";
6
8
  import { removeIndent } from "./Base.mjs";
9
+ const logger = serverLogger.getChild("SpecificationParser");
7
10
  export function SpecificationParser(B) {
8
11
  return class SpecificationParser extends B {
9
12
  parseSpecification() {
@@ -20,14 +23,14 @@ export function SpecificationParser(B) {
20
23
  try {
21
24
  Object.assign(c4Specification.elements, this.parseElementSpecificationNode(elementSpec));
22
25
  } catch (e) {
23
- logWarnError(e);
26
+ logger.warn(loggable(e));
24
27
  }
25
28
  }
26
29
  for (const deploymentNodeSpec of specifications.flatMap((s) => s.deploymentNodes.filter(isValid))) {
27
30
  try {
28
31
  Object.assign(c4Specification.deployments, this.parseElementSpecificationNode(deploymentNodeSpec));
29
32
  } catch (e) {
30
- logWarnError(e);
33
+ logger.warn(loggable(e));
31
34
  }
32
35
  }
33
36
  const relations_specs = specifications.flatMap((s) => s.relationships.filter(this.isValid));
@@ -49,10 +52,10 @@ export function SpecificationParser(B) {
49
52
  );
50
53
  c4Specification.relationships[kindName] = {
51
54
  ...bodyProps,
52
- ...toRelationshipStyleExcludeDefaults(props, this.isValid)
55
+ ...toRelationshipStyle(props.filter(ast.isRelationshipStyleProperty), this.isValid)
53
56
  };
54
57
  } catch (e) {
55
- logWarnError(e);
58
+ logger.warn(loggable(e));
56
59
  }
57
60
  }
58
61
  const tags_specs = specifications.flatMap((s) => s.tags.filter(this.isValid));
@@ -68,7 +71,7 @@ export function SpecificationParser(B) {
68
71
  };
69
72
  }
70
73
  } catch (e) {
71
- logWarnError(e);
74
+ logger.warn(loggable(e));
72
75
  }
73
76
  }
74
77
  const colors_specs = specifications.flatMap((s) => s.colors.filter(isValid));
@@ -83,7 +86,7 @@ export function SpecificationParser(B) {
83
86
  color: nonNullable(this.parseColorLiteral(color), `Color "${colorName}" is not valid: ${color}`)
84
87
  };
85
88
  } catch (e) {
86
- logWarnError(e);
89
+ logger.warn(loggable(e));
87
90
  }
88
91
  }
89
92
  }
@@ -101,25 +104,16 @@ export function SpecificationParser(B) {
101
104
  filter((p) => this.isValid(p)),
102
105
  mapToObj((p) => [p.key, p.value])
103
106
  );
104
- const { title, description, technology } = this.parseTitleDescriptionTechnology(
105
- {
106
- title: void 0,
107
- description: void 0,
108
- technology: void 0
109
- },
110
- bodyProps
111
- );
107
+ const baseProps = this.parseBaseProps(bodyProps);
112
108
  const notation = removeIndent(parseMarkdownAsString(bodyProps.notation));
113
109
  return {
114
- [kindName]: {
115
- ...title && { title },
116
- ...description && { description },
117
- ...technology && { technology },
118
- ...notation && { notation },
119
- ...tags && { tags },
110
+ [kindName]: exact({
111
+ ...baseProps,
112
+ notation,
113
+ tags: tags ?? void 0,
120
114
  ...links && c4.isNonEmptyArray(links) && { links },
121
115
  style
122
- }
116
+ })
123
117
  };
124
118
  }
125
119
  };
@@ -3,7 +3,7 @@ export class LikeC4ValueConverter extends DefaultValueConverter {
3
3
  runConverter(rule, input, cstNode) {
4
4
  if (rule.name === "MarkdownString") {
5
5
  if (input.startsWith('"""') && input.endsWith('"""') || input.startsWith(`'''`) && input.endsWith(`'''`)) {
6
- input = input.slice(3, -3);
6
+ input = input.slice(2, -2);
7
7
  }
8
8
  return ValueConverter.convertString(input);
9
9
  }
@@ -1,4 +1,5 @@
1
1
  import * as c4 from '@likec4/core';
2
+ import type { Except, Writable } from 'type-fest';
2
3
  import { type ParsedAstDynamicView, type ParsedAstElementView, ast } from '../../ast';
3
4
  import type { WithDeploymentView } from './DeploymentViewParser';
4
5
  import type { WithPredicates } from './PredicatesParser';
@@ -18,8 +19,16 @@ export declare function ViewsParser<TBase extends WithPredicates & WithDeploymen
18
19
  parseDynamicElementView(astNode: ast.DynamicView, additionalStyles: ViewRuleStyleOrGlobalRef[]): ParsedAstDynamicView;
19
20
  parseDynamicViewRule(astRule: ast.DynamicViewRule): c4.DynamicViewRule;
20
21
  parseDynamicViewIncludePredicate(astRule: ast.DynamicViewIncludePredicate): c4.DynamicViewIncludeRule;
21
- parseDynamicParallelSteps(node: ast.DynamicViewParallelSteps): c4.DynamicViewParallelSteps;
22
- parseDynamicStep(node: ast.DynamicViewStep): c4.DynamicViewStep;
22
+ parseDynamicParallelSteps(node: ast.DynamicViewParallelSteps): c4.DynamicStepsParallel;
23
+ /**
24
+ * @returns non-empty array in case of step chain A -> B -> C
25
+ */
26
+ parseDynamicStep(node: ast.DynamicViewStep): c4.DynamicStep | c4.DynamicStepsSeries;
27
+ recursiveParseDynamicStepChain(node: ast.DynamicStepChain, callstack?: Array<[source: c4.Fqn, target: c4.Fqn]>): c4.DynamicStep[];
28
+ parseDynamicStepSingle(node: ast.DynamicStepSingle): c4.DynamicStep;
29
+ parseAbstractDynamicStep(astnode: ast.AbstractDynamicStep): Writable<Except<c4.DynamicStep, "source", {
30
+ requireExactProps: true;
31
+ }>>;
23
32
  parsePredicate(astNode: ast.ExpressionV2): c4.ModelExpression;
24
33
  parseElementPredicate(astNode: ast.FqnExprOrWith): c4.ModelFqnExpr.Any;
25
34
  parseElementPredicateOrWhere(astNode: ast.FqnExprOrWhere): c4.ModelFqnExpr.OrWhere;
@@ -42,6 +51,7 @@ export declare function ViewsParser<TBase extends WithPredicates & WithDeploymen
42
51
  parseFqnExpressions(astNode: ast.FqnExpressions): c4.FqnExpr[];
43
52
  parseRelationExprOrWith(astNode: ast.RelationExprOrWith): c4.RelationExpr.Any;
44
53
  parseRelationExprWith(astNode: ast.RelationExprWith): c4.RelationExpr.Custom;
54
+ parseCustomRelationProperties(custom: ast.CustomRelationProperties | undefined): Except<c4.RelationExpr.Custom["customRelation"], "expr">;
45
55
  parseRelationExprOrWhere(astNode: ast.RelationExprOrWhere): c4.RelationExpr.OrWhere;
46
56
  parseRelationExprWhere(astNode: ast.RelationExprWhere): c4.RelationExpr.Where;
47
57
  parseRelationExpr(astNode: ast.RelationExpr): c4.RelationExpr.OrWhere;
@@ -70,16 +80,19 @@ export declare function ViewsParser<TBase extends WithPredicates & WithDeploymen
70
80
  parseColorLiteral(astNode: ast.ColorLiteral): c4.ColorLiteral | undefined;
71
81
  parseElementStyle(elementProps: Array<ast.ElementProperty> | ast.ElementStyleProperty | undefined): import("../../ast").ParsedElementStyle;
72
82
  parseStyleProps(styleProps: Array<ast.StyleProperty> | undefined): import("../../ast").ParsedElementStyle;
73
- parseTitleDescriptionTechnology(inlineProps: {
74
- title?: string | undefined;
75
- description?: string | undefined;
76
- technology?: string | undefined;
77
- }, bodyProps: {
83
+ parseBaseProps(props: {
78
84
  title?: ast.MarkdownOrString | undefined;
85
+ summary?: ast.MarkdownOrString | undefined;
79
86
  description?: ast.MarkdownOrString | undefined;
80
87
  technology?: ast.MarkdownOrString | undefined;
88
+ }, override?: {
89
+ title?: string | undefined;
90
+ summary?: string | undefined;
91
+ description?: string | undefined;
92
+ technology?: string | undefined;
81
93
  }): {
82
94
  title?: string;
95
+ summary?: c4.MarkdownOrString;
83
96
  description?: c4.MarkdownOrString;
84
97
  technology?: string;
85
98
  };
@@ -1,6 +1,7 @@
1
1
  import * as c4 from "@likec4/core";
2
2
  import { invariant, isNonEmptyArray, nonexhaustive } from "@likec4/core";
3
- import { filter, find, isArray, isDefined, isEmpty, isNonNullish, isTruthy, mapToObj, pipe } from "remeda";
3
+ import { loggable } from "@likec4/log";
4
+ import { filter, find, isDefined, isEmpty, isNonNullish, isNumber, isTruthy, last, mapToObj, pipe } from "remeda";
4
5
  import {
5
6
  ast,
6
7
  parseMarkdownAsString,
@@ -8,11 +9,12 @@ import {
8
9
  toColor,
9
10
  ViewOps
10
11
  } from "../../ast.mjs";
11
- import { logger, logWarnError } from "../../logger.mjs";
12
+ import { logger as mainLogger } from "../../logger.mjs";
12
13
  import { stringHash } from "../../utils/index.mjs";
13
14
  import { elementRef } from "../../utils/elementRef.mjs";
14
15
  import { parseViewManualLayout } from "../../view-utils/manual-layout.mjs";
15
16
  import { removeIndent, toSingleLine } from "./Base.mjs";
17
+ const logger = mainLogger.getChild("ViewsParser");
16
18
  export function ViewsParser(B) {
17
19
  return class ViewsParser extends B {
18
20
  parseViews() {
@@ -22,7 +24,7 @@ export function ViewsParser(B) {
22
24
  try {
23
25
  return isValid(s) ? this.parseViewRuleStyleOrGlobalRef(s) : [];
24
26
  } catch (e) {
25
- logWarnError(e);
27
+ logger.warn(loggable(e));
26
28
  return [];
27
29
  }
28
30
  });
@@ -50,7 +52,7 @@ export function ViewsParser(B) {
50
52
  view2.title = folder + " / " + (view2.title || view2.id);
51
53
  }
52
54
  } catch (e) {
53
- logWarnError(e);
55
+ logger.warn(loggable(e));
54
56
  }
55
57
  }
56
58
  }
@@ -77,8 +79,7 @@ export function ViewsParser(B) {
77
79
  viewOf ?? ""
78
80
  );
79
81
  }
80
- const { title = null, description = null } = this.parseTitleDescriptionTechnology(
81
- {},
82
+ const { title = null, description = null } = this.parseBaseProps(
82
83
  pipe(
83
84
  body.props,
84
85
  filter((p) => this.isValid(p)),
@@ -103,7 +104,7 @@ export function ViewsParser(B) {
103
104
  try {
104
105
  return this.isValid(n) ? this.parseElementViewRule(n) : [];
105
106
  } catch (e) {
106
- logWarnError(e);
107
+ logger.warn(loggable(e));
107
108
  return [];
108
109
  }
109
110
  })
@@ -150,7 +151,7 @@ export function ViewsParser(B) {
150
151
  exprs.unshift(expr);
151
152
  }
152
153
  } catch (e) {
153
- logWarnError(e);
154
+ logger.warn(loggable(e));
154
155
  }
155
156
  if (!prev) {
156
157
  break;
@@ -190,7 +191,7 @@ export function ViewsParser(B) {
190
191
  }
191
192
  nonexhaustive(rule);
192
193
  } catch (e) {
193
- logWarnError(e);
194
+ logger.warn(loggable(e));
194
195
  }
195
196
  }
196
197
  return {
@@ -229,8 +230,7 @@ export function ViewsParser(B) {
229
230
  astPath
230
231
  );
231
232
  }
232
- const { title = null, description = null } = this.parseTitleDescriptionTechnology(
233
- {},
233
+ const { title = null, description = null } = this.parseBaseProps(
234
234
  pipe(
235
235
  props,
236
236
  filter(ast.isViewStringProperty),
@@ -257,7 +257,7 @@ export function ViewsParser(B) {
257
257
  try {
258
258
  return isValid(n) ? this.parseDynamicViewRule(n) : [];
259
259
  } catch (e) {
260
- logWarnError(e);
260
+ logger.warn(loggable(e));
261
261
  return [];
262
262
  }
263
263
  }, [])
@@ -272,7 +272,7 @@ export function ViewsParser(B) {
272
272
  }
273
273
  }
274
274
  } catch (e) {
275
- logWarnError(e);
275
+ logger.warn(loggable(e));
276
276
  }
277
277
  return acc;
278
278
  }, []),
@@ -306,46 +306,113 @@ export function ViewsParser(B) {
306
306
  }
307
307
  }
308
308
  } catch (e) {
309
- logWarnError(e);
309
+ logger.warn(loggable(e));
310
310
  }
311
311
  iter = iter.prev;
312
312
  }
313
313
  return { include };
314
314
  }
315
315
  parseDynamicParallelSteps(node) {
316
+ const parallelId = pathInsideDynamicView(node);
317
+ const __parallel = node.steps.map((step) => this.parseDynamicStep(step));
318
+ invariant(isNonEmptyArray(__parallel), "Dynamic parallel steps must have at least one step");
316
319
  return {
317
- __parallel: node.steps.map((step) => this.parseDynamicStep(step))
320
+ parallelId,
321
+ __parallel
318
322
  };
319
323
  }
324
+ /**
325
+ * @returns non-empty array in case of step chain A -> B -> C
326
+ */
320
327
  parseDynamicStep(node) {
328
+ if (ast.isDynamicStepSingle(node)) {
329
+ invariant(this.isValid(node));
330
+ return this.parseDynamicStepSingle(node);
331
+ }
332
+ const __series = this.recursiveParseDynamicStepChain(node);
333
+ invariant(isNonEmptyArray(__series), "Dynamic step chain must have at least one step");
334
+ return {
335
+ seriesId: pathInsideDynamicView(node),
336
+ __series
337
+ };
338
+ }
339
+ recursiveParseDynamicStepChain(node, callstack) {
340
+ if (ast.isDynamicStepSingle(node.source)) {
341
+ if (!this.isValid(node.source)) {
342
+ return [];
343
+ }
344
+ const previous2 = this.parseDynamicStepSingle(node.source);
345
+ if (previous2.isBackward) {
346
+ return [];
347
+ }
348
+ const thisStep2 = {
349
+ ...this.parseAbstractDynamicStep(node),
350
+ source: previous2.target
351
+ };
352
+ if (thisStep2.target === previous2.source) {
353
+ thisStep2.isBackward = true;
354
+ } else if (callstack) {
355
+ callstack.push([previous2.source, previous2.target]);
356
+ callstack.push([thisStep2.source, thisStep2.target]);
357
+ }
358
+ return [previous2, thisStep2];
359
+ }
360
+ callstack ??= [];
361
+ const allprevious = this.recursiveParseDynamicStepChain(node.source, callstack);
362
+ if (!isNonEmptyArray(allprevious) || !this.isValid(node)) {
363
+ return [];
364
+ }
365
+ const previous = last(allprevious);
366
+ const thisStep = {
367
+ ...this.parseAbstractDynamicStep(node),
368
+ source: previous.target
369
+ };
370
+ const index = callstack.findIndex(([source, target]) => source === thisStep.target && target === thisStep.source);
371
+ if (index !== -1) {
372
+ thisStep.isBackward = true;
373
+ callstack.splice(index, callstack.length - index);
374
+ } else {
375
+ callstack.push([thisStep.source, thisStep.target]);
376
+ }
377
+ return [...allprevious, thisStep];
378
+ }
379
+ parseDynamicStepSingle(node) {
321
380
  const sourceEl = elementRef(node.source);
322
381
  if (!sourceEl) {
323
382
  throw new Error("Invalid reference to source");
324
383
  }
325
- const targetEl = elementRef(node.target);
326
- if (!targetEl) {
327
- throw new Error("Invalid reference to target");
328
- }
329
- let source = this.resolveFqn(sourceEl);
330
- let target = this.resolveFqn(targetEl);
331
- const title = removeIndent(node.title) ?? null;
332
- let step = {
333
- source,
334
- target,
335
- title
384
+ let baseStep = {
385
+ ...this.parseAbstractDynamicStep(node),
386
+ source: this.resolveFqn(sourceEl)
336
387
  };
337
388
  if (node.isBackward) {
338
- step = {
339
- source: target,
340
- target: source,
341
- title,
389
+ baseStep = {
390
+ ...baseStep,
391
+ source: baseStep.target,
392
+ target: baseStep.source,
342
393
  isBackward: true
343
394
  };
344
395
  }
345
- if (!isArray(node.custom?.props)) {
346
- return step;
396
+ return baseStep;
397
+ }
398
+ parseAbstractDynamicStep(astnode) {
399
+ const targetEl = elementRef(astnode.target);
400
+ if (!targetEl) {
401
+ throw new Error("Invalid reference to target");
402
+ }
403
+ const step = {
404
+ target: this.resolveFqn(targetEl),
405
+ astPath: pathInsideDynamicView(astnode)
406
+ };
407
+ const title = removeIndent(astnode.title);
408
+ if (title) {
409
+ step.title = title;
410
+ }
411
+ const kind = astnode.kind?.ref?.name ?? astnode.dotKind?.kind.ref?.name;
412
+ if (kind) {
413
+ step.kind = kind;
347
414
  }
348
- for (const prop of node.custom.props) {
415
+ for (const prop of astnode.custom?.props ?? []) {
349
416
  try {
350
417
  switch (true) {
351
418
  case ast.isRelationNavigateToProperty(prop): {
@@ -358,7 +425,14 @@ export function ViewsParser(B) {
358
425
  case ast.isRelationStringProperty(prop):
359
426
  case ast.isNotationProperty(prop): {
360
427
  if (isDefined(prop.value)) {
361
- step[prop.key] = removeIndent(parseMarkdownAsString(prop.value)) ?? "";
428
+ if (prop.key === "description") {
429
+ const value = removeIndent(prop.value);
430
+ if (value) {
431
+ step.description = value;
432
+ }
433
+ } else {
434
+ step[prop.key] = removeIndent(parseMarkdownAsString(prop.value)) ?? "";
435
+ }
362
436
  }
363
437
  break;
364
438
  }
@@ -391,10 +465,26 @@ export function ViewsParser(B) {
391
465
  nonexhaustive(prop);
392
466
  }
393
467
  } catch (e) {
394
- logWarnError(e);
468
+ logger.warn(loggable(e));
395
469
  }
396
470
  }
397
471
  return step;
398
472
  }
399
473
  };
400
474
  }
475
+ function pathInsideDynamicView(_node) {
476
+ let node = _node;
477
+ let path = [];
478
+ while (!ast.isDynamicViewBody(node)) {
479
+ if (isNumber(node.$containerIndex)) {
480
+ path.unshift(
481
+ `@${node.$containerIndex}`
482
+ );
483
+ }
484
+ path.unshift(
485
+ `/${node.$containerProperty ?? "__invalid__"}`
486
+ );
487
+ node = node.$container;
488
+ }
489
+ return path.join("");
490
+ }
@@ -1,5 +1,5 @@
1
1
  import { Location, Range, TextEdit } from 'vscode-languageserver-types';
2
- import { type ParsedLikeC4LangiumDocument } from '../ast';
2
+ import type { ParsedLikeC4LangiumDocument } from '../ast';
3
3
  import type { LikeC4Services } from '../module';
4
4
  import type { ChangeView } from '../protocol';
5
5
  export declare class LikeC4ModelChanges {
package/dist/module.mjs CHANGED
@@ -1,3 +1,4 @@
1
+ import { onNextTick } from "@likec4/core/utils";
1
2
  import { GraphvizWasmAdapter, QueueGraphvizLayoter } from "@likec4/layouts";
2
3
  import {
3
4
  DocumentState,
@@ -144,9 +145,9 @@ export function createLanguageServices(context, module, module2, module3) {
144
145
  shared.ServiceRegistry.register(likec4);
145
146
  registerValidationChecks(likec4);
146
147
  if (!context.connection) {
147
- shared.workspace.ConfigurationProvider.initialized({});
148
+ void shared.workspace.ConfigurationProvider.initialized({});
148
149
  } else {
149
- likec4.Rpc.init();
150
+ onNextTick(() => likec4.Rpc.init());
150
151
  }
151
152
  return { shared, likec4 };
152
153
  }
@@ -176,18 +176,42 @@ export declare namespace BuildDocuments {
176
176
  * If LSP has multiple projects, the projectId is required.
177
177
  */
178
178
  export declare namespace Locate {
179
- type Params = {
179
+ type Params =
180
+ /**
181
+ * Locate an element by its fqn
182
+ */
183
+ {
180
184
  element: Fqn;
181
185
  projectId?: string | undefined;
182
186
  property?: string;
183
- } | {
187
+ }
188
+ /**
189
+ * Locate a relation by its id
190
+ */
191
+ | {
184
192
  projectId?: string | undefined;
185
193
  relation: RelationId;
186
- } | {
194
+ }
195
+ /**
196
+ * Locate a deployment by its fqn
197
+ */
198
+ | {
187
199
  deployment: DeploymentFqn;
188
200
  projectId?: string | undefined;
189
201
  property?: string;
190
- } | {
202
+ }
203
+ /**
204
+ * Locate a step in a dynamic view by its astPath
205
+ */
206
+ | {
207
+ view: ViewId;
208
+ astPath: string;
209
+ projectId?: string | undefined;
210
+ }
211
+ /**
212
+ * Locate a view by its id
213
+ */
214
+ | {
191
215
  view: ViewId;
192
216
  projectId?: string | undefined;
193
217
  };
@@ -27,8 +27,7 @@ export class LikeC4ScopeComputation extends DefaultScopeComputation {
27
27
  views,
28
28
  globals,
29
29
  likec4lib,
30
- deployments,
31
- imports
30
+ deployments
32
31
  } = document.parseResult.value;
33
32
  this.exportLibrary(likec4lib, docExports, document);
34
33
  this.exportSpecification(specifications, docExports, document);
@@ -205,7 +204,7 @@ export class LikeC4ScopeComputation extends DefaultScopeComputation {
205
204
  let imported = imports;
206
205
  while (imported) {
207
206
  descendants.push(
208
- this.descriptions.createDescription(imported, imported.imported.$refText, document)
207
+ this.descriptions.createDescription(imported, imported.imported.$refText)
209
208
  );
210
209
  imported = imported.prev;
211
210
  }
@@ -1,6 +1,6 @@
1
1
  import { type ProjectId } from '@likec4/core';
2
2
  import { type AstNodeDescription, type ReferenceInfo, type Scope, type Stream, DefaultScopeProvider } from 'langium';
3
- import { type AstNodeDescriptionWithFqn, ast } from '../ast';
3
+ import { ast } from '../ast';
4
4
  import type { DeploymentsIndex, FqnIndex } from '../model';
5
5
  import type { LikeC4Services } from '../module';
6
6
  import type { IndexManager } from '../workspace';
@@ -10,7 +10,7 @@ export declare class LikeC4ScopeProvider extends DefaultScopeProvider {
10
10
  protected readonly indexManager: IndexManager;
11
11
  constructor(services: LikeC4Services);
12
12
  getScope(context: ReferenceInfo): Scope;
13
- protected genUniqueDescedants(of: () => ast.Element | ast.DeploymentNode | undefined): Generator<Stream<AstNodeDescriptionWithFqn>, void, any>;
13
+ protected genUniqueDescedants(of: () => ast.Element | ast.DeploymentNode | undefined): Generator<Stream<import("../ast").AstNodeDescriptionWithFqn>, void, any>;
14
14
  protected genScopeExtendElement({ element }: ast.ExtendElement): Generator<AstNodeDescription>;
15
15
  protected genScopeElementView({ viewOf, extends: ext }: ast.ElementView): Generator<AstNodeDescription>;
16
16
  protected getScopeForStrictFqnRef(projectId: ProjectId, container: ast.StrictFqnRef, context: ReferenceInfo): any;
@@ -2,12 +2,10 @@ import { nonexhaustive } from "@likec4/core";
2
2
  import {
3
3
  AstUtils,
4
4
  DefaultScopeProvider,
5
- DONE_RESULT,
6
5
  EMPTY_SCOPE,
7
6
  EMPTY_STREAM,
8
7
  MapScope,
9
8
  stream,
10
- StreamImpl,
11
9
  StreamScope
12
10
  } from "langium";
13
11
  import { ast, isFqnRefInsideGlobals, isFqnRefInsideModel } from "../ast.mjs";
@@ -81,6 +79,14 @@ export class LikeC4ScopeProvider extends DefaultScopeProvider {
81
79
  *genScopeExtendElement({ element }) {
82
80
  if (element.el.$nodeDescription) {
83
81
  yield element.el.$nodeDescription;
82
+ yield {
83
+ ...element.el.$nodeDescription,
84
+ name: "this"
85
+ };
86
+ yield {
87
+ ...element.el.$nodeDescription,
88
+ name: "it"
89
+ };
84
90
  }
85
91
  yield* this.genUniqueDescedants(() => elementRef(element));
86
92
  }
@@ -231,16 +237,3 @@ export class LikeC4ScopeProvider extends DefaultScopeProvider {
231
237
  return this.getProjectScope(projectId, referenceType, context);
232
238
  }
233
239
  }
234
- function lazyStream(fn) {
235
- return new StreamImpl(
236
- () => {
237
- return fn().iterator();
238
- },
239
- (iterator) => {
240
- if (iterator) {
241
- return iterator.next();
242
- }
243
- return DONE_RESULT;
244
- }
245
- );
246
- }
@@ -1,5 +1,6 @@
1
1
  import type { LikeC4ProjectJsonConfig } from '@likec4/config';
2
2
  import type { ComputedLikeC4ModelData } from '@likec4/core';
3
+ import { type LangiumDocument } from 'langium';
3
4
  import type { LiteralUnion } from 'type-fest';
4
5
  import { URI } from 'vscode-uri';
5
6
  import type { LikeC4LangiumDocument } from '../ast';
@@ -9,6 +10,7 @@ export declare function createTestServices(options?: {
9
10
  }): {
10
11
  services: any;
11
12
  addDocument: (input: string, uri?: string) => Promise<LikeC4LangiumDocument>;
13
+ removeDocument: (doc: LangiumDocument | URI) => Promise<void>;
12
14
  parse: (input: string, uri?: string) => Promise<LikeC4LangiumDocument>;
13
15
  validate: (input: string | LikeC4LangiumDocument, uri?: string) => Promise<{
14
16
  document: LikeC4LangiumDocument;