@likec4/language-server 1.27.3 → 1.28.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 (113) hide show
  1. package/dist/LikeC4LanguageServices.js +6 -7
  2. package/dist/ast.d.ts +16 -9
  3. package/dist/ast.js +58 -79
  4. package/dist/bundled.mjs +2161 -2141
  5. package/dist/config/schema.d.ts +3 -3
  6. package/dist/config/schema.js +12 -5
  7. package/dist/documentation/documentation-provider.js +3 -1
  8. package/dist/formatting/LikeC4Formatter.d.ts +0 -2
  9. package/dist/formatting/LikeC4Formatter.js +24 -53
  10. package/dist/generated/ast.d.ts +128 -233
  11. package/dist/generated/ast.js +136 -308
  12. package/dist/generated/grammar.js +1 -1
  13. package/dist/lsp/CompletionProvider.d.ts +3 -0
  14. package/dist/lsp/CompletionProvider.js +128 -113
  15. package/dist/lsp/DocumentLinkProvider.js +6 -3
  16. package/dist/lsp/HoverProvider.js +3 -1
  17. package/dist/lsp/SemanticTokenProvider.js +33 -43
  18. package/dist/model/builder/MergedSpecification.d.ts +5 -3
  19. package/dist/model/builder/MergedSpecification.js +21 -7
  20. package/dist/model/builder/buildModel.d.ts +6 -1
  21. package/dist/model/builder/buildModel.js +20 -15
  22. package/dist/model/deployments-index.js +4 -2
  23. package/dist/model/fqn-index.d.ts +4 -2
  24. package/dist/model/fqn-index.js +28 -5
  25. package/dist/model/model-builder.d.ts +2 -2
  26. package/dist/model/model-builder.js +54 -16
  27. package/dist/model/model-locator.js +7 -4
  28. package/dist/model/model-parser.d.ts +215 -52
  29. package/dist/model/model-parser.js +6 -2
  30. package/dist/model/parser/Base.d.ts +11 -2
  31. package/dist/model/parser/Base.js +138 -3
  32. package/dist/model/parser/DeploymentModelParser.d.ts +19 -2
  33. package/dist/model/parser/DeploymentModelParser.js +19 -29
  34. package/dist/model/parser/DeploymentViewParser.d.ts +18 -2
  35. package/dist/model/parser/DeploymentViewParser.js +6 -24
  36. package/dist/model/parser/FqnRefParser.d.ts +18 -3
  37. package/dist/model/parser/FqnRefParser.js +264 -40
  38. package/dist/model/parser/GlobalsParser.d.ts +35 -18
  39. package/dist/model/parser/ImportsParser.d.ts +32 -0
  40. package/dist/model/parser/ImportsParser.js +26 -0
  41. package/dist/model/parser/ModelParser.d.ts +26 -2
  42. package/dist/model/parser/ModelParser.js +21 -41
  43. package/dist/model/parser/PredicatesParser.d.ts +35 -12
  44. package/dist/model/parser/PredicatesParser.js +20 -271
  45. package/dist/model/parser/SpecificationParser.d.ts +8 -0
  46. package/dist/model/parser/SpecificationParser.js +5 -9
  47. package/dist/model/parser/ViewsParser.d.ts +36 -19
  48. package/dist/model/parser/ViewsParser.js +16 -12
  49. package/dist/model-change/changeElementStyle.d.ts +2 -2
  50. package/dist/model-change/changeElementStyle.js +9 -6
  51. package/dist/references/name-provider.js +8 -2
  52. package/dist/references/scope-computation.d.ts +1 -1
  53. package/dist/references/scope-computation.js +33 -3
  54. package/dist/references/scope-provider.d.ts +7 -8
  55. package/dist/references/scope-provider.js +59 -41
  56. package/dist/shared/NodeKindProvider.js +4 -2
  57. package/dist/test/testServices.d.ts +2 -0
  58. package/dist/test/testServices.js +4 -1
  59. package/dist/utils/elementRef.d.ts +1 -1
  60. package/dist/utils/elementRef.js +6 -1
  61. package/dist/utils/fqnRef.d.ts +3 -0
  62. package/dist/utils/fqnRef.js +15 -4
  63. package/dist/utils/index.d.ts +1 -0
  64. package/dist/utils/index.js +9 -0
  65. package/dist/utils/projectId.d.ts +2 -1
  66. package/dist/utils/projectId.js +11 -1
  67. package/dist/validation/_shared.js +2 -2
  68. package/dist/validation/deployment-checks.js +24 -10
  69. package/dist/validation/element-ref.d.ts +4 -0
  70. package/dist/validation/element-ref.js +12 -0
  71. package/dist/validation/element.d.ts +1 -1
  72. package/dist/validation/element.js +1 -1
  73. package/dist/validation/imports.d.ts +5 -0
  74. package/dist/validation/imports.js +30 -0
  75. package/dist/validation/index.d.ts +1 -1
  76. package/dist/validation/index.js +47 -45
  77. package/dist/validation/relation.d.ts +2 -2
  78. package/dist/validation/relation.js +24 -27
  79. package/dist/validation/specification.d.ts +9 -9
  80. package/dist/validation/specification.js +9 -9
  81. package/dist/validation/view-predicates/{element-with.d.ts → fqn-expr-with.d.ts} +1 -1
  82. package/dist/validation/view-predicates/fqn-expr-with.js +42 -0
  83. package/dist/validation/view-predicates/fqn-ref-expr.d.ts +4 -0
  84. package/dist/validation/view-predicates/fqn-ref-expr.js +53 -0
  85. package/dist/validation/view-predicates/incoming.d.ts +1 -1
  86. package/dist/validation/view-predicates/incoming.js +2 -2
  87. package/dist/validation/view-predicates/index.d.ts +6 -6
  88. package/dist/validation/view-predicates/index.js +6 -6
  89. package/dist/validation/view-predicates/outgoing.d.ts +1 -1
  90. package/dist/validation/view-predicates/outgoing.js +8 -4
  91. package/dist/validation/view-predicates/{expanded-element.d.ts → relation-expr.d.ts} +1 -1
  92. package/dist/validation/view-predicates/relation-expr.js +39 -0
  93. package/dist/validation/view-predicates/relation-with.d.ts +1 -1
  94. package/dist/validation/view-predicates/relation-with.js +8 -5
  95. package/dist/views/likec4-views.d.ts +1 -0
  96. package/dist/views/likec4-views.js +23 -4
  97. package/dist/workspace/AstNodeDescriptionProvider.d.ts +1 -1
  98. package/dist/workspace/AstNodeDescriptionProvider.js +2 -3
  99. package/dist/workspace/IndexManager.d.ts +1 -1
  100. package/dist/workspace/IndexManager.js +5 -4
  101. package/dist/workspace/LangiumDocuments.d.ts +1 -1
  102. package/dist/workspace/LangiumDocuments.js +3 -5
  103. package/dist/workspace/ProjectsManager.d.ts +25 -7
  104. package/dist/workspace/ProjectsManager.js +76 -32
  105. package/dist/workspace/WorkspaceManager.d.ts +4 -5
  106. package/dist/workspace/WorkspaceManager.js +53 -20
  107. package/package.json +17 -13
  108. package/dist/validation/dynamic-view-rule.d.ts +0 -4
  109. package/dist/validation/dynamic-view-rule.js +0 -17
  110. package/dist/validation/view-predicates/element-with.js +0 -31
  111. package/dist/validation/view-predicates/expanded-element.js +0 -12
  112. package/dist/validation/view-predicates/expression-v2.d.ts +0 -5
  113. package/dist/validation/view-predicates/expression-v2.js +0 -83
@@ -15,15 +15,15 @@ const asViewStyleRule = (target, style, indent = 0) => {
15
15
  ];
16
16
  };
17
17
  const isMatchingViewRule = (fqn, index) => (rule) => {
18
- if (!ast.isViewRuleStyle(rule)) {
18
+ if (!ast.isViewRuleStyle(rule) && !ast.isDeploymentViewRuleStyle(rule)) {
19
19
  return false;
20
20
  }
21
- const target = rule.target.value;
22
- if (!target || isTruthy(rule.target.prev) || !ast.isElementRef(target)) {
21
+ const target = rule.targets.value;
22
+ if (!target || isTruthy(rule.targets.prev) || target.$type !== "FqnRefExpr" || isTruthy(target.selector)) {
23
23
  return false;
24
24
  }
25
- const ref = target.el.ref;
26
- const _fqn = ref ? index.getFqn(ref) : null;
25
+ const ref = target.ref?.value?.ref;
26
+ const _fqn = ref ? index.resolve(ref) : null;
27
27
  return _fqn === fqn;
28
28
  };
29
29
  export function changeElementStyle(services, {
@@ -39,7 +39,10 @@ export function changeElementStyle(services, {
39
39
  invariant(insertPos, "insertPos is not defined");
40
40
  const indent = viewCstNode.range.start.character + 2;
41
41
  const fqnIndex = services.likec4.FqnIndex;
42
- const styleRules = filter(viewAst.body.rules, ast.isViewRuleStyle);
42
+ const styleRules = filter(
43
+ viewAst.body.rules,
44
+ (r) => ast.isViewRuleStyle(r) || ast.isDeploymentViewRuleStyle(r)
45
+ );
43
46
  const viewOf = view.__ === "element" ? view.viewOf : null;
44
47
  const existing = [];
45
48
  const insert = [];
@@ -16,8 +16,11 @@ export class LikeC4NameProvider extends DefaultNameProvider {
16
16
  if (isNamed(node)) {
17
17
  return node.name;
18
18
  }
19
+ if (ast.isImported(node)) {
20
+ return node.imported.$refText;
21
+ }
19
22
  if (ast.isDeployedInstance(node)) {
20
- return node.element.el.$refText;
23
+ return node.target.modelElement.value.$refText;
21
24
  }
22
25
  return void 0;
23
26
  }
@@ -25,8 +28,11 @@ export class LikeC4NameProvider extends DefaultNameProvider {
25
28
  if (isNamed(node)) {
26
29
  return super.getNameNode(node);
27
30
  }
31
+ if (ast.isImported(node)) {
32
+ return node.imported.$refNode;
33
+ }
28
34
  if (ast.isDeployedInstance(node)) {
29
- return node.element.el.$refNode;
35
+ return node.target.modelElement.value.$refNode;
30
36
  }
31
37
  return void 0;
32
38
  }
@@ -3,7 +3,7 @@ import type { CancellationToken } from 'vscode-languageserver';
3
3
  import { type LikeC4LangiumDocument, ast } from '../ast';
4
4
  import type { LikeC4Services } from '../module';
5
5
  type ElementsContainer = ast.Model | ast.ElementBody | ast.ExtendElementBody;
6
- type DeploymentsContainer = ast.ModelDeployments | ast.DeploymentNodeBody | ast.ExtendDeploymentBody;
6
+ type DeploymentsContainer = ast.ModelDeployments | ast.DeploymentNodeBody | ast.ExtendDeploymentBody | ast.DeployedInstanceBody;
7
7
  export declare class LikeC4ScopeComputation extends DefaultScopeComputation {
8
8
  constructor(services: LikeC4Services);
9
9
  computeExports(document: LikeC4LangiumDocument, _cancelToken?: CancellationToken): Promise<AstNodeDescription[]>;
@@ -21,7 +21,15 @@ export class LikeC4ScopeComputation extends DefaultScopeComputation {
21
21
  async computeExports(document, _cancelToken) {
22
22
  const docExports = [];
23
23
  try {
24
- const { specifications, models, views, globals, likec4lib, deployments } = document.parseResult.value;
24
+ const {
25
+ specifications,
26
+ models,
27
+ views,
28
+ globals,
29
+ likec4lib,
30
+ deployments,
31
+ imports
32
+ } = document.parseResult.value;
25
33
  this.exportLibrary(likec4lib, docExports, document);
26
34
  this.exportSpecification(specifications, docExports, document);
27
35
  this.exportModel(models, docExports, document);
@@ -193,6 +201,19 @@ export class LikeC4ScopeComputation extends DefaultScopeComputation {
193
201
  logWarnError(e);
194
202
  }
195
203
  }
204
+ for (const imports of root.imports.flatMap((i) => i.imports)) {
205
+ try {
206
+ let imported = imports;
207
+ while (imported) {
208
+ descendants.push(
209
+ this.descriptions.createDescription(imported, imported.imported.$refText, document)
210
+ );
211
+ imported = imported.prev;
212
+ }
213
+ } catch (e) {
214
+ logWarnError(e);
215
+ }
216
+ }
196
217
  uniqueDescriptions(descendants).forEach((desc) => {
197
218
  scopes.add(root, desc);
198
219
  });
@@ -212,6 +233,10 @@ export class LikeC4ScopeComputation extends DefaultScopeComputation {
212
233
  localScope.add(el.name, this.descriptions.createDescription(el, el.name, document));
213
234
  }
214
235
  subcontainer = el.body;
236
+ if (subcontainer) {
237
+ scopes.add(subcontainer, this.descriptions.createDescription(el, "this", document));
238
+ scopes.add(subcontainer, this.descriptions.createDescription(el, "it", document));
239
+ }
215
240
  } else if (ast.isExtendElement(el)) {
216
241
  subcontainer = el.body;
217
242
  }
@@ -248,17 +273,22 @@ export class LikeC4ScopeComputation extends DefaultScopeComputation {
248
273
  if (ast.isDeploymentRelation(el)) {
249
274
  continue;
250
275
  }
276
+ let subcontainer = el.body;
251
277
  if (!ast.isExtendDeployment(el)) {
252
278
  let name = this.nameProvider.getName(el);
253
279
  if (isTruthy(name)) {
254
280
  const desc = this.descriptions.createDescription(el, name, document);
255
281
  localScope.add(name, desc);
256
282
  }
283
+ if (subcontainer) {
284
+ scopes.add(subcontainer, this.descriptions.createDescription(el, "this", document));
285
+ scopes.add(subcontainer, this.descriptions.createDescription(el, "it", document));
286
+ }
257
287
  }
258
- if (!ast.isDeployedInstance(el) && el.body) {
288
+ if (subcontainer) {
259
289
  try {
260
290
  descedants.push(
261
- ...this.processDeployments(el.body, scopes, document)
291
+ ...this.processDeployments(subcontainer, scopes, document)
262
292
  );
263
293
  } catch (e) {
264
294
  logWarnError(e);
@@ -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 { ast } from '../ast';
3
+ import { type AstNodeDescriptionWithFqn, 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,14 +10,13 @@ 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<import("../ast").AstNodeDescriptionWithFqn>, void, any>;
14
- protected streamScopeElementRef(ref: ast.ElementRef): Stream<AstNodeDescription>;
15
- protected streamScopeExtendElement({ element }: ast.ExtendElement): Stream<AstNodeDescription>;
16
- protected streamScopeElementView({ viewOf, extends: ext }: ast.ElementView): Stream<AstNodeDescription>;
13
+ protected genUniqueDescedants(of: () => ast.Element | ast.DeploymentNode | undefined): Generator<Stream<AstNodeDescriptionWithFqn>, void, any>;
14
+ protected genScopeExtendElement({ element }: ast.ExtendElement): Generator<AstNodeDescription>;
15
+ protected genScopeElementView({ viewOf, extends: ext }: ast.ElementView): Generator<AstNodeDescription>;
17
16
  protected getScopeForStrictFqnRef(projectId: ProjectId, container: ast.StrictFqnRef, context: ReferenceInfo): any;
18
- protected streamScopeExtendDeployment({ deploymentNode }: ast.ExtendDeployment): Stream<AstNodeDescription>;
17
+ protected genScopeExtendDeployment({ deploymentNode }: ast.ExtendDeployment): Generator<AstNodeDescription>;
19
18
  protected streamForFqnRef(projectId: ProjectId, container: ast.FqnRef, context: ReferenceInfo): Stream<AstNodeDescription>;
20
- protected genScopeForFqnRef(projectId: ProjectId, container: ast.FqnRef, context: ReferenceInfo): Generator<any, void, any>;
19
+ protected genScopeForParentlessFqnRef(projectId: ProjectId, container: ast.FqnRef, context: ReferenceInfo): Generator<AstNodeDescription>;
21
20
  /**
22
21
  * Computes the scope for a given reference context.
23
22
  *
@@ -29,7 +28,7 @@ export declare class LikeC4ScopeProvider extends DefaultScopeProvider {
29
28
  * It then iterates through the container hierarchy, collecting relevant scopes based on the reference type and container type.
30
29
  * Finally, it combines the collected scopes with the global scope to produce the final scope.
31
30
  */
32
- protected computeScope(projectId: ProjectId, context: ReferenceInfo, referenceType?: any): Generator<any, void, any>;
31
+ protected computeScope(projectId: ProjectId, context: ReferenceInfo, referenceType?: any): Generator<AstNodeDescription>;
33
32
  /**
34
33
  * Create a global scope filtered for the given reference type.
35
34
  */
@@ -10,7 +10,7 @@ import {
10
10
  StreamImpl,
11
11
  StreamScope
12
12
  } from "langium";
13
- import { ast } from "../ast.js";
13
+ import { ast, isFqnRefInsideGlobals, isFqnRefInsideModel } from "../ast.js";
14
14
  import { logWarnError } from "../logger.js";
15
15
  import { projectIdFrom } from "../utils/index.js";
16
16
  import { elementRef, readStrictFqn } from "../utils/elementRef.js";
@@ -40,6 +40,10 @@ export class LikeC4ScopeProvider extends DefaultScopeProvider {
40
40
  if (referenceType !== ast.Element) {
41
41
  return this.getProjectScope(projectId, referenceType, context);
42
42
  }
43
+ if (ast.isImported(container)) {
44
+ const projectId2 = projectIdFrom(container);
45
+ return new StreamScope(this.fqnIndex.rootElements(projectId2));
46
+ }
43
47
  if (ast.isStrictFqnElementRef(container) && context.property === "el") {
44
48
  const parent = container.parent;
45
49
  if (!parent) {
@@ -47,22 +51,6 @@ export class LikeC4ScopeProvider extends DefaultScopeProvider {
47
51
  }
48
52
  return new StreamScope(this.fqnIndex.directChildrenOf(projectId, readStrictFqn(parent)));
49
53
  }
50
- if (ast.isElementRef(container) && context.property === "el") {
51
- const parent = container.parent;
52
- if (parent) {
53
- return new StreamScope(this.streamScopeElementRef(parent));
54
- }
55
- if (context.reference.$refText === "this" || context.reference.$refText === "it") {
56
- const closestElement = AstUtils.getContainerOfType(container, ast.isElement);
57
- if (closestElement) {
58
- return new MapScope([
59
- this.descriptions.createDescription(closestElement, context.reference.$refText)
60
- ]);
61
- } else {
62
- return EMPTY_SCOPE;
63
- }
64
- }
65
- }
66
54
  return new StreamScope(stream(this.computeScope(projectId, context)));
67
55
  } catch (e) {
68
56
  logWarnError(e);
@@ -90,23 +78,26 @@ export class LikeC4ScopeProvider extends DefaultScopeProvider {
90
78
  yield* this.deploymentsIndex.uniqueDescedants(projectId, fqn);
91
79
  }
92
80
  }
93
- streamScopeElementRef(ref) {
94
- return stream(this.genUniqueDescedants(() => ref.el.ref));
95
- }
96
- streamScopeExtendElement({ element }) {
97
- return stream([element.el.$nodeDescription]).nonNullable().concat(this.genUniqueDescedants(() => elementRef(element)));
81
+ *genScopeExtendElement({ element }) {
82
+ if (element.el.$nodeDescription) {
83
+ yield element.el.$nodeDescription;
84
+ }
85
+ yield* this.genUniqueDescedants(() => elementRef(element));
98
86
  }
99
- streamScopeElementView({ viewOf, extends: ext }) {
87
+ *genScopeElementView({ viewOf, extends: ext }) {
100
88
  if (viewOf) {
101
- return stream([viewOf.el.$nodeDescription]).nonNullable().concat(this.genUniqueDescedants(() => elementRef(viewOf)));
89
+ if (viewOf.modelElement.value.$nodeDescription) {
90
+ yield viewOf.modelElement.value.$nodeDescription;
91
+ }
92
+ yield* this.genUniqueDescedants(() => elementRef(viewOf));
93
+ return;
102
94
  }
103
95
  if (ext) {
104
- return stream([ext]).flatMap((v) => {
105
- const view = v.view.ref;
106
- return view ? this.streamScopeElementView(view) : EMPTY_STREAM;
107
- });
96
+ const view = ext.view.ref;
97
+ if (view) {
98
+ yield* this.genScopeElementView(view);
99
+ }
108
100
  }
109
- return EMPTY_STREAM;
110
101
  }
111
102
  getScopeForStrictFqnRef(projectId, container, context) {
112
103
  const parent = container.parent;
@@ -117,37 +108,64 @@ export class LikeC4ScopeProvider extends DefaultScopeProvider {
117
108
  this.deploymentsIndex.directChildrenOf(projectId, readStrictFqn(parent)).filter((desc) => this.reflection.isSubtype(desc.type, ast.DeploymentNode))
118
109
  );
119
110
  }
120
- streamScopeExtendDeployment({ deploymentNode }) {
121
- return stream([deploymentNode.value.$nodeDescription]).nonNullable().concat(this.genUniqueDescedants(() => {
111
+ *genScopeExtendDeployment({ deploymentNode }) {
112
+ if (deploymentNode.value.$nodeDescription) {
113
+ yield deploymentNode.value.$nodeDescription;
114
+ }
115
+ yield* this.genUniqueDescedants(() => {
122
116
  const target = deploymentNode.value.ref;
123
117
  return target && ast.isDeploymentNode(target) ? target : void 0;
124
- }));
118
+ });
125
119
  }
126
120
  streamForFqnRef(projectId, container, context) {
127
121
  const parent = container.parent;
128
122
  if (!parent) {
129
- return stream(this.genScopeForFqnRef(projectId, container, context));
123
+ return stream(this.genScopeForParentlessFqnRef(projectId, container, context));
130
124
  }
131
125
  const parentRef = parent.value.ref;
132
126
  if (!parentRef) {
133
127
  return EMPTY_STREAM;
134
128
  }
129
+ if (ast.isImported(parentRef)) {
130
+ return stream(this.genUniqueDescedants(() => {
131
+ return parentRef.imported.ref;
132
+ }));
133
+ }
135
134
  if (ast.isDeploymentNode(parentRef)) {
136
135
  return stream(this.genUniqueDescedants(() => parentRef));
137
136
  }
138
137
  if (ast.isDeployedInstance(parentRef)) {
139
- return stream(this.streamScopeElementRef(parentRef.element));
138
+ return stream(this.genUniqueDescedants(() => {
139
+ const target = parentRef.target.modelElement.value.ref;
140
+ if (ast.isImported(target)) {
141
+ return target.imported.ref;
142
+ }
143
+ return ast.isElement(target) ? target : void 0;
144
+ }));
140
145
  }
141
146
  if (ast.isElement(parentRef)) {
142
147
  return stream(this.genUniqueDescedants(() => parentRef));
143
148
  }
144
149
  return nonexhaustive(parentRef);
145
150
  }
146
- *genScopeForFqnRef(projectId, container, context) {
147
- yield* this.computeScope(projectId, context, ast.DeploymentNode);
148
- yield* this.computeScope(projectId, context, ast.DeployedInstance);
149
- if (AstUtils.hasContainerOfType(container, ast.isDeploymentView)) {
151
+ *genScopeForParentlessFqnRef(projectId, container, context) {
152
+ if (AstUtils.hasContainerOfType(container, ast.isElementRef) || isFqnRefInsideModel(container)) {
150
153
  yield* this.computeScope(projectId, context, ast.Element);
154
+ } else if (isFqnRefInsideGlobals(container)) {
155
+ yield* this.computeScope(projectId, context, ast.Element);
156
+ yield* this.computeScope(projectId, context, ast.DeploymentNode);
157
+ yield* this.computeScope(projectId, context, ast.DeployedInstance);
158
+ } else {
159
+ yield* this.computeScope(projectId, context, ast.DeploymentNode);
160
+ yield* this.computeScope(projectId, context, ast.DeployedInstance);
161
+ if (AstUtils.hasContainerOfType(container, ast.isDeploymentViewBody)) {
162
+ yield* this.computeScope(projectId, context, ast.Element);
163
+ }
164
+ }
165
+ const doc = getDocument(container);
166
+ const precomputed = doc.precomputedScopes;
167
+ if (precomputed) {
168
+ yield* precomputed.values().filter((nd) => this.reflection.isSubtype(nd.type, ast.Imported));
151
169
  }
152
170
  }
153
171
  /**
@@ -178,13 +196,13 @@ export class LikeC4ScopeProvider extends DefaultScopeProvider {
178
196
  yield* elements;
179
197
  }
180
198
  if (isDeploymentReference && ast.isExtendDeploymentBody(container)) {
181
- yield* this.streamScopeExtendDeployment(container.$container);
199
+ yield* this.genScopeExtendDeployment(container.$container);
182
200
  }
183
201
  if (isElementReference && ast.isExtendElementBody(container)) {
184
- yield* this.streamScopeExtendElement(container.$container);
202
+ yield* this.genScopeExtendElement(container.$container);
185
203
  }
186
204
  if (isElementReference && ast.isElementViewBody(container)) {
187
- yield* this.streamScopeElementView(container.$container);
205
+ yield* this.genScopeElementView(container.$container);
188
206
  }
189
207
  container = container.$container;
190
208
  }
@@ -17,7 +17,8 @@ export class NodeKindProvider {
17
17
  ast.Element,
18
18
  ast.ExtendElement,
19
19
  ast.DeploymentNode,
20
- ast.DeployedInstance
20
+ ast.DeployedInstance,
21
+ ast.Imported
21
22
  ):
22
23
  return SymbolKind.Constructor;
23
24
  case hasType(
@@ -67,7 +68,8 @@ export class NodeKindProvider {
67
68
  ast.Element,
68
69
  ast.DeploymentNode,
69
70
  ast.DeployedInstance,
70
- ast.ExtendElement
71
+ ast.ExtendElement,
72
+ ast.Imported
71
73
  ):
72
74
  return CompletionItemKind.Constructor;
73
75
  case hasType(
@@ -20,7 +20,9 @@ export declare function createTestServices(workspace?: string): {
20
20
  format: (input: string | LikeC4LangiumDocument, uri?: string) => Promise<any>;
21
21
  };
22
22
  export declare function createMultiProjectTestServices<const Projects extends Record<string, Record<string, string>>>(data: Projects): Promise<{
23
+ services: any;
23
24
  projects: { readonly [K in keyof Projects]: { readonly [L in keyof Projects[K]]: LikeC4LangiumDocument; }; };
25
+ projectsManager: any;
24
26
  /**
25
27
  * Add document outside of projects
26
28
  */
@@ -141,7 +141,8 @@ export async function createMultiProjectTestServices(data) {
141
141
  const folderUri = UriUtils.joinPath(URI.parse(workspace), "src", name);
142
142
  services.shared.workspace.ProjectsManager.registerProject({
143
143
  config: {
144
- name
144
+ name,
145
+ exclude: ["node_modules"]
145
146
  },
146
147
  folderUri
147
148
  });
@@ -164,7 +165,9 @@ export async function createMultiProjectTestServices(data) {
164
165
  return model.$model;
165
166
  }
166
167
  return {
168
+ services,
167
169
  projects,
170
+ projectsManager: services.shared.workspace.ProjectsManager,
168
171
  /**
169
172
  * Add document outside of projects
170
173
  */
@@ -1,5 +1,5 @@
1
1
  import type * as c4 from '@likec4/core';
2
- import type { ast } from '../ast';
2
+ import { ast } from '../ast';
3
3
  /**
4
4
  * Returns referenced AST Element
5
5
  */
@@ -1,5 +1,10 @@
1
+ import { ast } from "../ast.js";
1
2
  export function elementRef(node) {
2
- return node.el.ref;
3
+ let el = ast.isStrictFqnElementRef(node) ? node.el.ref : node.modelElement.value.ref;
4
+ if (el?.$type === "Imported") {
5
+ el = el.imported.ref;
6
+ }
7
+ return el?.$type === "Element" ? el : void 0;
3
8
  }
4
9
  export function readStrictFqn(node) {
5
10
  const name = [node.$type === "StrictFqnRef" ? node.value.$refText : node.el.$refText];
@@ -1,6 +1,9 @@
1
1
  import { ast } from '../ast';
2
+ export declare function referenceableParent(node: ast.FqnRef): ast.Referenceable | null;
2
3
  export declare function instanceRef(deploymentRef: ast.FqnRef): ast.DeployedInstance | null;
3
4
  export declare function deploymentNodeRef(deploymentRef: ast.FqnRef): ast.DeploymentNode | null;
5
+ export declare function importsRef(node: ast.FqnRef): ast.Imported | null;
6
+ export declare function isImportsRef(node: ast.FqnRef): boolean;
4
7
  export declare function isReferenceToLogicalModel(node: ast.FqnRef): boolean;
5
8
  /**
6
9
  * Returns true if node references deployment model
@@ -1,6 +1,12 @@
1
1
  import { AstUtils } from "langium";
2
2
  import { isNullish } from "remeda";
3
3
  import { ast } from "../ast.js";
4
+ export function referenceableParent(node) {
5
+ while (node.parent) {
6
+ node = node.parent;
7
+ }
8
+ return node.value.ref ?? null;
9
+ }
4
10
  export function instanceRef(deploymentRef) {
5
11
  let referenceable;
6
12
  while (referenceable = deploymentRef.value?.ref) {
@@ -25,11 +31,16 @@ export function deploymentNodeRef(deploymentRef) {
25
31
  const artifact = instanceRef(deploymentRef);
26
32
  return artifact ? AstUtils.getContainerOfType(artifact, ast.isDeploymentNode) ?? null : null;
27
33
  }
34
+ export function importsRef(node) {
35
+ const referenceable = referenceableParent(node);
36
+ return referenceable?.$type === "Imported" ? referenceable : null;
37
+ }
38
+ export function isImportsRef(node) {
39
+ return !!importsRef(node);
40
+ }
28
41
  export function isReferenceToLogicalModel(node) {
29
- while (node.parent) {
30
- node = node.parent;
31
- }
32
- return ast.isElement(node.value.ref);
42
+ const referenceable = referenceableParent(node);
43
+ return referenceable?.$type === "Element";
33
44
  }
34
45
  export function isReferenceToDeploymentModel(node) {
35
46
  let referenceable;
@@ -3,3 +3,4 @@ export * from './elementRef';
3
3
  export * from './fqnRef';
4
4
  export * from './projectId';
5
5
  export * from './stringHash';
6
+ export declare function safeCall<T>(fn: () => T): T | undefined;
@@ -1,5 +1,14 @@
1
+ import { logger } from "../logger.js";
1
2
  export * from "./disposable.js";
2
3
  export * from "./elementRef.js";
3
4
  export * from "./fqnRef.js";
4
5
  export * from "./projectId.js";
5
6
  export * from "./stringHash.js";
7
+ export function safeCall(fn) {
8
+ try {
9
+ return fn();
10
+ } catch (e) {
11
+ logger.debug(`Safe call failed`, { error: e });
12
+ return void 0;
13
+ }
14
+ }
@@ -1,3 +1,4 @@
1
1
  import { type ProjectId } from '@likec4/core';
2
2
  import { type AstNode, type LangiumDocument } from 'langium';
3
- export declare function projectIdFrom(value: AstNode | LangiumDocument): ProjectId;
3
+ import { ast } from '../ast';
4
+ export declare function projectIdFrom(value: AstNode | LangiumDocument | ast.ImportsFromPoject | ast.Imported): ProjectId;
@@ -1,6 +1,16 @@
1
- import { nonNullable } from "@likec4/core";
1
+ import { invariant, nonNullable } from "@likec4/core";
2
2
  import { AstUtils, isAstNode } from "langium";
3
+ import { ast } from "../ast.js";
3
4
  export function projectIdFrom(value) {
5
+ if (ast.isImported(value)) {
6
+ while (value.$type === "Imported" && value.$container) {
7
+ value = value.$container;
8
+ }
9
+ invariant(ast.isImportsFromPoject(value));
10
+ }
11
+ if (ast.isImportsFromPoject(value)) {
12
+ return value.project;
13
+ }
4
14
  const doc = isAstNode(value) ? AstUtils.getDocument(value) : value;
5
15
  return nonNullable(doc.likec4ProjectId, () => `Invalid state, document ${doc.uri} has no project ID assigned`);
6
16
  }
@@ -1,5 +1,5 @@
1
1
  import { isPromise } from "remeda";
2
- import { logWarnError } from "../logger.js";
2
+ import { logger } from "../logger.js";
3
3
  export const RESERVED_WORDS = [
4
4
  "this",
5
5
  "it",
@@ -19,7 +19,7 @@ export function tryOrLog(fn) {
19
19
  } catch (e) {
20
20
  const message = e instanceof Error ? e.message : String(e);
21
21
  accept("error", `Validation failed: ${message}`, { node });
22
- logWarnError(e);
22
+ logger.debug(`Validation failed: ${message}`, { error: e });
23
23
  }
24
24
  };
25
25
  }
@@ -73,15 +73,6 @@ export const deployedInstanceChecks = (services) => {
73
73
  export const deploymentRelationChecks = (services) => {
74
74
  const ModelParser = services.likec4.ModelParser;
75
75
  return tryOrLog((el, accept) => {
76
- const source = el.source?.value?.ref;
77
- if (!source) {
78
- let sourceCstText = el.source?.$cstNode?.text ?? "";
79
- accept("error", `DeploymentRelation source '${sourceCstText}' not resolved`, {
80
- node: el,
81
- property: "source"
82
- });
83
- return;
84
- }
85
76
  const target = el.target?.value?.ref;
86
77
  if (!target) {
87
78
  let targetCstText = el.target?.$cstNode?.text ?? "";
@@ -93,7 +84,23 @@ export const deploymentRelationChecks = (services) => {
93
84
  }
94
85
  const doc = getDocument(el);
95
86
  const parser = ModelParser.forDocument(doc);
96
- const sourceFqnRef = parser.parseFqnRef(el.source);
87
+ let sourceFqnRef;
88
+ try {
89
+ sourceFqnRef = parser._resolveDeploymentRelationSource(el);
90
+ } catch (e) {
91
+ accept("error", "DeploymentRelation source not resolved", {
92
+ node: el,
93
+ property: "source"
94
+ });
95
+ return;
96
+ }
97
+ if (FqnRef.isImportRef(sourceFqnRef)) {
98
+ accept("error", "DeploymentRelation cannot refer imported model (not implemented yet)", {
99
+ node: el,
100
+ property: "source"
101
+ });
102
+ return;
103
+ }
97
104
  if (FqnRef.isModelRef(sourceFqnRef)) {
98
105
  accept("error", "DeploymentRelation must refer deployment element", {
99
106
  node: el,
@@ -102,6 +109,13 @@ export const deploymentRelationChecks = (services) => {
102
109
  return;
103
110
  }
104
111
  const targetFqnRef = parser.parseFqnRef(el.target);
112
+ if (FqnRef.isImportRef(targetFqnRef)) {
113
+ accept("error", "DeploymentRelation cannot refer imported model (not implemented yet)", {
114
+ node: el,
115
+ property: "target"
116
+ });
117
+ return;
118
+ }
105
119
  if (FqnRef.isModelRef(targetFqnRef)) {
106
120
  accept("error", "DeploymentRelation must refer deployment element", {
107
121
  node: el,
@@ -0,0 +1,4 @@
1
+ import { type ValidationCheck } from 'langium';
2
+ import type { ast } from '../ast';
3
+ import type { LikeC4Services } from '../module';
4
+ export declare const checkElementRef: (services: LikeC4Services) => ValidationCheck<ast.ElementRef>;
@@ -0,0 +1,12 @@
1
+ import { isReferenceToDeploymentModel } from "../utils/index.js";
2
+ import { tryOrLog } from "./_shared.js";
3
+ export const checkElementRef = (services) => {
4
+ return tryOrLog((el, accept) => {
5
+ if (isReferenceToDeploymentModel(el.modelElement)) {
6
+ accept("error", "Only model elements allowed here", {
7
+ node: el,
8
+ property: "modelElement"
9
+ });
10
+ }
11
+ });
12
+ };
@@ -1,4 +1,4 @@
1
1
  import { type ValidationCheck } from 'langium';
2
2
  import type { ast } from '../ast';
3
3
  import type { LikeC4Services } from '../module';
4
- export declare const elementChecks: (services: LikeC4Services) => ValidationCheck<ast.Element>;
4
+ export declare const checkElement: (services: LikeC4Services) => ValidationCheck<ast.Element>;
@@ -2,7 +2,7 @@ import { AstUtils } from "langium";
2
2
  import { projectIdFrom } from "../utils/index.js";
3
3
  import { RESERVED_WORDS, tryOrLog } from "./_shared.js";
4
4
  const { getDocument } = AstUtils;
5
- export const elementChecks = (services) => {
5
+ export const checkElement = (services) => {
6
6
  const fqnIndex = services.likec4.FqnIndex;
7
7
  const locator = services.workspace.AstNodeLocator;
8
8
  return tryOrLog((el, accept) => {
@@ -0,0 +1,5 @@
1
+ import { type ValidationCheck } from 'langium';
2
+ import type { ast } from '../ast';
3
+ import type { LikeC4Services } from '../module';
4
+ export declare const checkImportsFromPoject: (services: LikeC4Services) => ValidationCheck<ast.ImportsFromPoject>;
5
+ export declare const checkImported: (services: LikeC4Services) => ValidationCheck<ast.Imported>;