@likec4/language-server 1.27.2 → 1.28.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 (111) 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 +2130 -2127
  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 +134 -306
  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 +15 -11
  49. package/dist/model-change/changeElementStyle.d.ts +2 -2
  50. package/dist/model-change/changeElementStyle.js +2 -1
  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/workspace/AstNodeDescriptionProvider.d.ts +1 -1
  96. package/dist/workspace/AstNodeDescriptionProvider.js +2 -3
  97. package/dist/workspace/IndexManager.d.ts +1 -1
  98. package/dist/workspace/IndexManager.js +5 -4
  99. package/dist/workspace/LangiumDocuments.d.ts +1 -1
  100. package/dist/workspace/LangiumDocuments.js +3 -5
  101. package/dist/workspace/ProjectsManager.d.ts +25 -7
  102. package/dist/workspace/ProjectsManager.js +76 -32
  103. package/dist/workspace/WorkspaceManager.d.ts +4 -5
  104. package/dist/workspace/WorkspaceManager.js +53 -20
  105. package/package.json +12 -10
  106. package/dist/validation/dynamic-view-rule.d.ts +0 -4
  107. package/dist/validation/dynamic-view-rule.js +0 -17
  108. package/dist/validation/view-predicates/element-with.js +0 -31
  109. package/dist/validation/view-predicates/expanded-element.js +0 -12
  110. package/dist/validation/view-predicates/expression-v2.d.ts +0 -5
  111. package/dist/validation/view-predicates/expression-v2.js +0 -83
@@ -1,17 +1,38 @@
1
- import { nonexhaustive, nonNullable } from "@likec4/core";
2
- import { isNonNullish } from "remeda";
3
- import { ast } from "../../ast.js";
1
+ import { invariant, nonexhaustive, nonNullable } from "@likec4/core";
2
+ import { isBoolean, isDefined, isNonNullish, isTruthy } from "remeda";
3
+ import { ast, parseAstOpacityProperty, parseAstSizeValue, toColor } from "../../ast.js";
4
4
  import { logWarnError } from "../../logger.js";
5
- import { instanceRef } from "../../utils/fqnRef.js";
5
+ import { projectIdFrom } from "../../utils/index.js";
6
+ import { importsRef, instanceRef } from "../../utils/fqnRef.js";
6
7
  import { parseWhereClause } from "../model-parser-where.js";
8
+ import { removeIndent } from "./Base.js";
7
9
  export function ExpressionV2Parser(B) {
8
10
  return class ExpressionV2Parser extends B {
9
11
  parseFqnRef(astNode) {
10
12
  const refValue = nonNullable(
11
- astNode.value.ref,
13
+ astNode.value?.ref,
12
14
  `FqnRef is empty ${astNode.$cstNode?.range.start.line}:${astNode.$cstNode?.range.start.character}`
13
15
  );
16
+ if (ast.isImported(refValue)) {
17
+ const fqnRef = {
18
+ project: projectIdFrom(refValue),
19
+ model: this.resolveFqn(
20
+ nonNullable(refValue.imported.ref, `FqnRef is empty of imported: ${refValue.$cstNode?.text}`)
21
+ )
22
+ };
23
+ this.doc.c4Imports.set(fqnRef.project, fqnRef.model);
24
+ return fqnRef;
25
+ }
14
26
  if (ast.isElement(refValue)) {
27
+ const imported = importsRef(astNode);
28
+ if (imported) {
29
+ const fqnRef = {
30
+ project: projectIdFrom(imported),
31
+ model: this.resolveFqn(refValue)
32
+ };
33
+ this.doc.c4Imports.set(fqnRef.project, fqnRef.model);
34
+ return fqnRef;
35
+ }
15
36
  const deployedInstanceAst = instanceRef(astNode);
16
37
  if (!deployedInstanceAst) {
17
38
  return {
@@ -32,12 +53,160 @@ export function ExpressionV2Parser(B) {
32
53
  }
33
54
  nonexhaustive(refValue);
34
55
  }
56
+ parseExpressionV2(astNode) {
57
+ if (ast.isFqnExprOrWith(astNode)) {
58
+ return this.parseFqnExprOrWith(astNode);
59
+ }
60
+ if (ast.isRelationExprOrWith(astNode)) {
61
+ return this.parseRelationExprOrWith(astNode);
62
+ }
63
+ nonexhaustive(astNode);
64
+ }
65
+ parseFqnExprOrWith(astNode) {
66
+ if (ast.isFqnExprWith(astNode)) {
67
+ return this.parseFqnExprWith(astNode);
68
+ }
69
+ if (ast.isFqnExprOrWhere(astNode)) {
70
+ return this.parseFqnExprOrWhere(astNode);
71
+ }
72
+ nonexhaustive(astNode);
73
+ }
74
+ parseFqnExprWith(astNode) {
75
+ const expr = this.parseFqnExprOrWhere(astNode.subject);
76
+ const props = astNode.custom?.props ?? [];
77
+ return props.reduce(
78
+ (acc, prop) => {
79
+ if (!this.isValid(prop)) {
80
+ return acc;
81
+ }
82
+ if (ast.isNavigateToProperty(prop)) {
83
+ const viewId = prop.value.view.$refText;
84
+ if (isTruthy(viewId)) {
85
+ acc.custom.navigateTo = viewId;
86
+ }
87
+ return acc;
88
+ }
89
+ if (ast.isElementStringProperty(prop)) {
90
+ if (isDefined(prop.value)) {
91
+ acc.custom[prop.key] = removeIndent(prop.value) || "";
92
+ }
93
+ return acc;
94
+ }
95
+ if (ast.isIconProperty(prop)) {
96
+ const value = this.parseIconProperty(prop);
97
+ if (isDefined(value)) {
98
+ acc.custom[prop.key] = value;
99
+ }
100
+ return acc;
101
+ }
102
+ if (ast.isColorProperty(prop)) {
103
+ const value = toColor(prop);
104
+ if (isDefined(value)) {
105
+ acc.custom[prop.key] = value;
106
+ }
107
+ return acc;
108
+ }
109
+ if (ast.isShapeProperty(prop)) {
110
+ if (isDefined(prop.value)) {
111
+ acc.custom[prop.key] = prop.value;
112
+ }
113
+ return acc;
114
+ }
115
+ if (ast.isBorderProperty(prop)) {
116
+ if (isDefined(prop.value)) {
117
+ acc.custom[prop.key] = prop.value;
118
+ }
119
+ return acc;
120
+ }
121
+ if (ast.isOpacityProperty(prop)) {
122
+ if (isDefined(prop.value)) {
123
+ acc.custom[prop.key] = parseAstOpacityProperty(prop);
124
+ }
125
+ return acc;
126
+ }
127
+ if (ast.isNotationProperty(prop)) {
128
+ if (isTruthy(prop.value)) {
129
+ acc.custom[prop.key] = removeIndent(prop.value);
130
+ }
131
+ return acc;
132
+ }
133
+ if (ast.isMultipleProperty(prop)) {
134
+ if (isBoolean(prop.value)) {
135
+ acc.custom[prop.key] = prop.value;
136
+ }
137
+ return acc;
138
+ }
139
+ if (ast.isShapeSizeProperty(prop)) {
140
+ if (isTruthy(prop.value)) {
141
+ acc.custom[prop.key] = parseAstSizeValue(prop);
142
+ }
143
+ return acc;
144
+ }
145
+ if (ast.isTextSizeProperty(prop)) {
146
+ if (isTruthy(prop.value)) {
147
+ acc.custom[prop.key] = parseAstSizeValue(prop);
148
+ }
149
+ return acc;
150
+ }
151
+ if (ast.isPaddingSizeProperty(prop)) {
152
+ if (isTruthy(prop.value)) {
153
+ acc.custom[prop.key] = parseAstSizeValue(prop);
154
+ }
155
+ return acc;
156
+ }
157
+ nonexhaustive(prop);
158
+ },
159
+ {
160
+ custom: {
161
+ expr
162
+ }
163
+ }
164
+ );
165
+ }
166
+ parseFqnExprOrWhere(astNode) {
167
+ if (ast.isFqnExprWhere(astNode)) {
168
+ return this.parseFqnExprWhere(astNode);
169
+ }
170
+ if (ast.isFqnExpr(astNode)) {
171
+ return this.parseFqnExpr(astNode);
172
+ }
173
+ nonexhaustive(astNode);
174
+ }
175
+ parseFqnExprWhere(astNode) {
176
+ invariant(!ast.isFqnExprWhere(astNode.subject), "FqnExprWhere is not allowed as subject of FqnExprWhere");
177
+ return {
178
+ where: {
179
+ expr: this.parseFqnExpr(astNode.subject),
180
+ condition: astNode.where ? parseWhereClause(astNode.where) : {
181
+ kind: { neq: "--always-true--" }
182
+ }
183
+ }
184
+ };
185
+ }
35
186
  parseFqnExpr(astNode) {
36
187
  if (ast.isWildcardExpression(astNode)) {
37
188
  return {
38
189
  wildcard: true
39
190
  };
40
191
  }
192
+ if (ast.isElementKindExpression(astNode)) {
193
+ invariant(astNode.kind?.ref, "ElementKindExpr kind is not resolved: " + astNode.$cstNode?.text);
194
+ return {
195
+ elementKind: astNode.kind.ref.name,
196
+ isEqual: astNode.isEqual
197
+ };
198
+ }
199
+ if (ast.isElementTagExpression(astNode)) {
200
+ invariant(astNode.tag?.ref, "ElementTagExpr tag is not resolved: " + astNode.$cstNode?.text);
201
+ let elementTag = astNode.tag.$refText;
202
+ if (elementTag.startsWith("#")) {
203
+ elementTag = elementTag.slice(1);
204
+ }
205
+ return {
206
+ elementTag,
207
+ isEqual: astNode.isEqual
208
+ };
209
+ }
41
210
  if (ast.isFqnRefExpr(astNode)) {
42
211
  return this.parseFqnRefExpr(astNode);
43
212
  }
@@ -65,16 +234,6 @@ export function ExpressionV2Parser(B) {
65
234
  return { ref };
66
235
  }
67
236
  }
68
- parseElementWhereExpr(astNode) {
69
- return {
70
- where: {
71
- expr: this.parseFqnExpr(astNode.subject),
72
- condition: astNode.where ? parseWhereClause(astNode.where) : {
73
- kind: { neq: "--always-true--" }
74
- }
75
- }
76
- };
77
- }
78
237
  parseFqnExpressions(astNode) {
79
238
  const exprs = [];
80
239
  let iter = astNode;
@@ -90,7 +249,75 @@ export function ExpressionV2Parser(B) {
90
249
  }
91
250
  return exprs.reverse();
92
251
  }
93
- parseRelationWhereExpr(astNode) {
252
+ parseRelationExprOrWith(astNode) {
253
+ if (ast.isRelationExprWith(astNode)) {
254
+ return this.parseRelationExprWith(astNode);
255
+ }
256
+ if (ast.isRelationExprOrWhere(astNode)) {
257
+ return this.parseRelationExprOrWhere(astNode);
258
+ }
259
+ nonexhaustive(astNode);
260
+ }
261
+ parseRelationExprWith(astNode) {
262
+ const expr = this.parseRelationExprOrWhere(astNode.subject);
263
+ const props = astNode.custom?.props ?? [];
264
+ return props.reduce(
265
+ (acc, prop) => {
266
+ if (ast.isRelationStringProperty(prop) || ast.isNotationProperty(prop) || ast.isNotesProperty(prop)) {
267
+ if (isDefined(prop.value)) {
268
+ acc.customRelation[prop.key] = removeIndent(prop.value) ?? "";
269
+ }
270
+ return acc;
271
+ }
272
+ if (ast.isArrowProperty(prop)) {
273
+ if (isTruthy(prop.value)) {
274
+ acc.customRelation[prop.key] = prop.value;
275
+ }
276
+ return acc;
277
+ }
278
+ if (ast.isColorProperty(prop)) {
279
+ const value = toColor(prop);
280
+ if (isTruthy(value)) {
281
+ acc.customRelation[prop.key] = value;
282
+ }
283
+ return acc;
284
+ }
285
+ if (ast.isLineProperty(prop)) {
286
+ if (isTruthy(prop.value)) {
287
+ acc.customRelation[prop.key] = prop.value;
288
+ }
289
+ return acc;
290
+ }
291
+ if (ast.isRelationNavigateToProperty(prop)) {
292
+ const viewId = prop.value.view.ref?.name;
293
+ if (isTruthy(viewId)) {
294
+ acc.customRelation.navigateTo = viewId;
295
+ }
296
+ return acc;
297
+ }
298
+ nonexhaustive(prop);
299
+ },
300
+ {
301
+ customRelation: {
302
+ expr
303
+ }
304
+ }
305
+ );
306
+ }
307
+ parseRelationExprOrWhere(astNode) {
308
+ if (ast.isRelationExprWhere(astNode)) {
309
+ return this.parseRelationExprWhere(astNode);
310
+ }
311
+ if (ast.isRelationExpr(astNode)) {
312
+ return this.parseRelationExpr(astNode);
313
+ }
314
+ nonexhaustive(astNode);
315
+ }
316
+ parseRelationExprWhere(astNode) {
317
+ invariant(
318
+ !ast.isRelationExprWhere(astNode.subject),
319
+ "RelationExprWhere is not allowed as subject of RelationExprWhere"
320
+ );
94
321
  return {
95
322
  where: {
96
323
  expr: this.parseRelationExpr(astNode.subject),
@@ -101,31 +328,28 @@ export function ExpressionV2Parser(B) {
101
328
  };
102
329
  }
103
330
  parseRelationExpr(astNode) {
104
- if (ast.isRelationPredicateWhere(astNode)) {
105
- }
106
- if (ast.isDirectedRelationExpr(astNode)) {
107
- return {
108
- source: this.parseFqnExpr(astNode.source.from),
109
- target: this.parseFqnExpr(astNode.target),
110
- isBidirectional: astNode.source.isBidirectional
111
- };
112
- }
113
- if (ast.isInOutRelationExpr(astNode)) {
114
- return {
115
- inout: this.parseFqnExpr(astNode.inout.to)
116
- };
117
- }
118
- if (ast.isOutgoingRelationExpr(astNode)) {
119
- return {
120
- outgoing: this.parseFqnExpr(astNode.from)
121
- };
122
- }
123
- if (ast.isIncomingRelationExpr(astNode)) {
124
- return {
125
- incoming: this.parseFqnExpr(astNode.to)
126
- };
331
+ switch (astNode.$type) {
332
+ case "DirectedRelationExpr":
333
+ return {
334
+ source: this.parseFqnExpr(astNode.source.from),
335
+ target: this.parseFqnExpr(astNode.target),
336
+ isBidirectional: astNode.source.isBidirectional
337
+ };
338
+ case "InOutRelationExpr":
339
+ return {
340
+ inout: this.parseFqnExpr(astNode.inout.to)
341
+ };
342
+ case "OutgoingRelationExpr":
343
+ return {
344
+ outgoing: this.parseFqnExpr(astNode.from)
345
+ };
346
+ case "IncomingRelationExpr":
347
+ return {
348
+ incoming: this.parseFqnExpr(astNode.to)
349
+ };
350
+ default:
351
+ nonexhaustive(astNode);
127
352
  }
128
- nonexhaustive(astNode);
129
353
  }
130
354
  };
131
355
  }
@@ -16,26 +16,46 @@ export declare function GlobalsParser<TBase extends WithViewsParser>(B: TBase):
16
16
  parseViewRuleStyleOrGlobalRef(astRule: ast.ViewRuleStyleOrGlobalRef): c4.ViewRuleStyleOrGlobalRef;
17
17
  parseViewRuleGroup(astNode: ast.ViewRuleGroup): c4.ViewRuleGroup;
18
18
  parseViewRuleStyle(astRule: ast.ViewRuleStyle | ast.GlobalStyle): c4.ViewRuleStyle;
19
- parseRuleStyle(styleProperties: ast.StyleProperty[], elementExpressionsIterator: ast.ElementExpressionsIterator, notationProperty?: ast.NotationProperty): c4.ViewRuleStyle;
19
+ parseRuleStyle(styleProperties: ast.StyleProperty[], elementExpressionsIterator: ast.FqnExpressions, notationProperty?: ast.NotationProperty): c4.ViewRuleStyle;
20
20
  parseViewRuleGlobalStyle(astRule: ast.ViewRuleGlobalStyle): c4.ViewRuleGlobalStyle;
21
21
  parseDynamicElementView(astNode: ast.DynamicView, additionalStyles: c4.ViewRuleStyleOrGlobalRef[]): import("../../ast").ParsedAstDynamicView;
22
22
  parseDynamicViewRule(astRule: ast.DynamicViewRule): c4.DynamicViewRule;
23
23
  parseDynamicViewIncludePredicate(astRule: ast.DynamicViewIncludePredicate): c4.DynamicViewIncludeRule;
24
24
  parseDynamicParallelSteps(node: ast.DynamicViewParallelSteps): c4.DynamicViewParallelSteps;
25
25
  parseDynamicStep(node: ast.DynamicViewStep): c4.DynamicViewStep;
26
- parsePredicate(astNode: ast.Predicate): c4.Expression;
27
- parseElementPredicate(astNode: ast.ElementPredicate): c4.ElementPredicateExpression;
28
- parseElementExpressionsIterator(astNode: ast.ElementExpressionsIterator): c4.ElementExpression[];
29
- parseElementExpression(astNode: ast.ElementExpression): c4.ElementExpression;
30
- parseElementPredicateWhere(astNode: ast.ElementPredicateWhere): c4.ElementWhereExpr;
31
- parseElementPredicateWith(astNode: ast.ElementPredicateWith): c4.CustomElementExpr;
32
- parseRelationPredicate(astNode: ast.RelationPredicate): c4.RelationPredicateExpression;
33
- parseRelationPredicateWhere(astNode: ast.RelationPredicateWhere): c4.RelationWhereExpr;
34
- parseRelationPredicateWith(astNode: ast.RelationPredicateWith, relation: c4.RelationExpression | c4.RelationWhereExpr): c4.CustomRelationExpr;
35
- parseRelationExpression(astNode: ast.RelationExpression): c4.RelationExpression;
26
+ parsePredicate(astNode: ast.ExpressionV2): c4.ModelLayer.Expression;
27
+ parseElementPredicate(astNode: ast.FqnExprOrWith): c4.ModelLayer.AnyFqnExpr;
28
+ parseElementPredicateOrWhere(astNode: ast.FqnExprOrWhere): c4.ModelLayer.FqnExprOrWhere;
29
+ parseElementExpression(astNode: ast.FqnExpr): c4.ModelLayer.FqnExpr;
30
+ parseElementPredicateWhere(astNode: ast.FqnExprWhere): c4.ModelLayer.FqnExpr.Where;
31
+ parseElementPredicateWith(astNode: ast.FqnExprWith): c4.ModelLayer.FqnExpr.Custom;
32
+ parseRelationPredicate(astNode: ast.RelationExprOrWith): c4.ModelLayer.AnyRelationExpr;
33
+ parseRelationPredicateOrWhere(astNode: ast.RelationExprOrWhere): c4.ModelLayer.RelationExprOrWhere;
34
+ parseRelationPredicateWhere(astNode: ast.RelationExprWhere): c4.ModelLayer.RelationExpr.Where;
35
+ parseRelationPredicateWith(astNode: ast.RelationExprWith): c4.ModelLayer.RelationExpr.Custom;
36
+ parseRelationExpression(astNode: ast.RelationExpr): c4.ModelLayer.RelationExpr;
37
+ parseFqnRef(astNode: ast.FqnRef): c4.FqnRef;
38
+ parseExpressionV2(astNode: ast.ExpressionV2): c4.ExpressionV2;
39
+ parseFqnExprOrWith(astNode: ast.FqnExprOrWith): c4.FqnExpr.Any;
40
+ parseFqnExprWith(astNode: ast.FqnExprWith): c4.FqnExpr.Custom;
41
+ parseFqnExprOrWhere(astNode: ast.FqnExprOrWhere): c4.FqnExpr.OrWhere;
42
+ parseFqnExprWhere(astNode: ast.FqnExprWhere): c4.FqnExpr.Where;
43
+ parseFqnExpr(astNode: ast.FqnExpr): c4.FqnExpr;
44
+ parseFqnRefExpr(astNode: ast.FqnRefExpr): c4.FqnExpr.NonWildcard;
45
+ parseFqnExpressions(astNode: ast.FqnExpressions): c4.FqnExpr[];
46
+ parseRelationExprOrWith(astNode: ast.RelationExprOrWith): c4.RelationExpr.Any;
47
+ parseRelationExprWith(astNode: ast.RelationExprWith): c4.RelationExpr.Custom;
48
+ parseRelationExprOrWhere(astNode: ast.RelationExprOrWhere): c4.RelationExpr.OrWhere;
49
+ parseRelationExprWhere(astNode: ast.RelationExprWhere): c4.RelationExpr.Where;
50
+ parseRelationExpr(astNode: ast.RelationExpr): c4.RelationExpr;
36
51
  isValid: import("../../validation").IsValidFn;
37
52
  readonly services: import("../..").LikeC4Services;
38
53
  readonly doc: import("../../ast").ParsedLikeC4LangiumDocument;
54
+ readonly project: {
55
+ id: c4.ProjectId;
56
+ folder: c4;
57
+ config: Readonly<import("../../config").ProjectConfig>;
58
+ };
39
59
  resolveFqn(node: ast.FqnReferenceable): c4.Fqn;
40
60
  getAstNodePath(node: c4): any;
41
61
  getMetadata(metadataAstNode: ast.MetadataProperty | undefined): {
@@ -49,21 +69,18 @@ export declare function GlobalsParser<TBase extends WithViewsParser>(B: TBase):
49
69
  }>(withTags?: E): c4.NonEmptyArray<c4.Tag> | null;
50
70
  convertLinks(source?: ast.LinkProperty["$container"]): c4.Link[] | undefined;
51
71
  parseLinks(source?: ast.LinkProperty["$container"]): c4.Link[] | undefined;
72
+ parseIconProperty(prop: ast.IconProperty | undefined): c4.IconUrl | undefined;
73
+ parseElementStyle(elementProps: Array<ast.ElementProperty> | ast.ElementStyleProperty | undefined): import("../../ast").ParsedElementStyle;
74
+ parseStyleProps(styleProps: Array<ast.StyleProperty> | undefined): import("../../ast").ParsedElementStyle;
52
75
  parseDeploymentView(astNode: ast.DeploymentView): import("../../ast").ParsedAstDeploymentView;
53
76
  parseDeploymentViewRule(astRule: ast.DeploymentViewRule): c4.DeploymentViewRule;
54
77
  parseDeploymentViewRulePredicate(astRule: ast.DeploymentViewRulePredicate): c4.DeploymentViewRulePredicate;
55
78
  parseDeploymentViewRuleStyle(astRule: ast.DeploymentViewRuleStyle): c4.DeploymentViewRuleStyle;
56
- parseFqnRef(astNode: ast.FqnRef): c4.FqnRef;
57
- parseFqnExpr(astNode: ast.FqnExpr): c4.FqnExpr;
58
- parseFqnRefExpr(astNode: ast.FqnRefExpr): c4.FqnExpr.NonWildcard;
59
- parseElementWhereExpr(astNode: ast.ElementPredicateWhereV2): c4.RelationExpr;
60
- parseFqnExpressions(astNode: ast.FqnExpressions): c4.FqnExpr[];
61
- parseRelationWhereExpr(astNode: ast.RelationPredicateWhereV2): c4.RelationExpr;
62
- parseRelationExpr(astNode: ast.RelationExpr): c4.RelationExpr;
63
79
  parseDeployment(): void;
64
80
  parseDeploymentNode(astNode: ast.DeploymentNode): import("../../ast").ParsedAstDeployment.Node;
65
81
  parseDeployedInstance(astNode: ast.DeployedInstance): import("../../ast").ParsedAstDeployment.Instance;
66
82
  parseExtendDeployment(astNode: ast.ExtendDeployment): import("../../ast").ParsedAstExtend | null;
83
+ _resolveDeploymentRelationSource(node: ast.DeploymentRelation): c4;
67
84
  parseDeploymentRelation(astNode: ast.DeploymentRelation): import("../../ast").ParsedAstDeploymentRelation;
68
85
  };
69
86
  } & TBase;
@@ -0,0 +1,32 @@
1
+ import { type ProjectId } from '@likec4/core';
2
+ import type { ast } from '../../ast';
3
+ import type { Base } from './Base';
4
+ export declare function ImportsParser<TBase extends Base>(B: TBase): {
5
+ new (...args: any[]): {
6
+ parseImports(): void;
7
+ isValid: import("../../validation").IsValidFn;
8
+ readonly services: import("../..").LikeC4Services;
9
+ readonly doc: import("../../ast").ParsedLikeC4LangiumDocument;
10
+ readonly project: {
11
+ id: ProjectId;
12
+ folder: ProjectId;
13
+ config: Readonly<import("../../config").ProjectConfig>;
14
+ };
15
+ resolveFqn(node: ast.FqnReferenceable): ProjectId;
16
+ getAstNodePath(node: ProjectId): any;
17
+ getMetadata(metadataAstNode: ast.MetadataProperty | undefined): {
18
+ [key: string]: string;
19
+ } | undefined;
20
+ convertTags<E extends {
21
+ tags?: ast.Tags;
22
+ }>(withTags?: E | undefined): any;
23
+ parseTags<E extends {
24
+ tags?: ast.Tags;
25
+ }>(withTags?: E): ProjectId<ProjectId> | null;
26
+ convertLinks(source?: ast.LinkProperty["$container"]): ProjectId[] | undefined;
27
+ parseLinks(source?: ast.LinkProperty["$container"]): ProjectId[] | undefined;
28
+ parseIconProperty(prop: ast.IconProperty | undefined): ProjectId | undefined;
29
+ parseElementStyle(elementProps: Array<ast.ElementProperty> | ast.ElementStyleProperty | undefined): import("../../ast").ParsedElementStyle;
30
+ parseStyleProps(styleProps: Array<ast.StyleProperty> | undefined): import("../../ast").ParsedElementStyle;
31
+ };
32
+ } & TBase;
@@ -0,0 +1,26 @@
1
+ import { nonNullable } from "@likec4/core";
2
+ import { logWarnError } from "../../logger.js";
3
+ export function ImportsParser(B) {
4
+ return class ImportsParser extends B {
5
+ parseImports() {
6
+ const imports = this.doc.parseResult.value.imports ?? [];
7
+ for (const importsFromPoject of imports) {
8
+ const project = importsFromPoject.project;
9
+ let imported = importsFromPoject.imports;
10
+ while (imported) {
11
+ try {
12
+ this.doc.c4Imports.set(
13
+ project,
14
+ this.resolveFqn(
15
+ nonNullable(imported.imported.ref, `ElementRef is empty of imported: ${imported.imported.$refText}`)
16
+ )
17
+ );
18
+ } catch (e) {
19
+ logWarnError(e);
20
+ }
21
+ imported = imported.prev;
22
+ }
23
+ }
24
+ }
25
+ };
26
+ }
@@ -1,16 +1,37 @@
1
1
  import type * as c4 from '@likec4/core';
2
+ import { FqnRef } from '@likec4/core/types';
2
3
  import { type ParsedAstElement, type ParsedAstExtend, type ParsedAstRelation, ast } from '../../ast';
3
- import { type Base } from './Base';
4
+ import type { WithExpressionV2 } from './FqnRefParser';
4
5
  export type WithModel = ReturnType<typeof ModelParser>;
5
- export declare function ModelParser<TBase extends Base>(B: TBase): {
6
+ export declare function ModelParser<TBase extends WithExpressionV2>(B: TBase): {
6
7
  new (...args: any[]): {
7
8
  parseModel(): void;
8
9
  parseElement(astNode: ast.Element): ParsedAstElement;
9
10
  parseExtendElement(astNode: ast.ExtendElement): ParsedAstExtend | null;
11
+ _resolveRelationSource(node: ast.Relation): FqnRef.ModelRef | FqnRef.ImportRef;
10
12
  parseRelation(astNode: ast.Relation): ParsedAstRelation;
13
+ parseFqnRef(astNode: ast.FqnRef): c4.FqnRef;
14
+ parseExpressionV2(astNode: ast.ExpressionV2): c4.ExpressionV2;
15
+ parseFqnExprOrWith(astNode: ast.FqnExprOrWith): c4.FqnExpr.Any;
16
+ parseFqnExprWith(astNode: ast.FqnExprWith): c4.FqnExpr.Custom;
17
+ parseFqnExprOrWhere(astNode: ast.FqnExprOrWhere): c4.FqnExpr.OrWhere;
18
+ parseFqnExprWhere(astNode: ast.FqnExprWhere): c4.FqnExpr.Where;
19
+ parseFqnExpr(astNode: ast.FqnExpr): c4.FqnExpr;
20
+ parseFqnRefExpr(astNode: ast.FqnRefExpr): c4.FqnExpr.NonWildcard;
21
+ parseFqnExpressions(astNode: ast.FqnExpressions): c4.FqnExpr[];
22
+ parseRelationExprOrWith(astNode: ast.RelationExprOrWith): c4.RelationExpr.Any;
23
+ parseRelationExprWith(astNode: ast.RelationExprWith): c4.RelationExpr.Custom;
24
+ parseRelationExprOrWhere(astNode: ast.RelationExprOrWhere): c4.RelationExpr.OrWhere;
25
+ parseRelationExprWhere(astNode: ast.RelationExprWhere): c4.RelationExpr.Where;
26
+ parseRelationExpr(astNode: ast.RelationExpr): c4.RelationExpr;
11
27
  isValid: import("../../validation").IsValidFn;
12
28
  readonly services: import("../..").LikeC4Services;
13
29
  readonly doc: import("../../ast").ParsedLikeC4LangiumDocument;
30
+ readonly project: {
31
+ id: c4.ProjectId;
32
+ folder: c4;
33
+ config: Readonly<import("../../config").ProjectConfig>;
34
+ };
14
35
  resolveFqn(node: ast.FqnReferenceable): c4.Fqn;
15
36
  getAstNodePath(node: c4): any;
16
37
  getMetadata(metadataAstNode: ast.MetadataProperty | undefined): {
@@ -24,5 +45,8 @@ export declare function ModelParser<TBase extends Base>(B: TBase): {
24
45
  }>(withTags?: E): c4.NonEmptyArray<c4.Tag> | null;
25
46
  convertLinks(source?: ast.LinkProperty["$container"]): c4.Link[] | undefined;
26
47
  parseLinks(source?: ast.LinkProperty["$container"]): c4.Link[] | undefined;
48
+ parseIconProperty(prop: ast.IconProperty | undefined): c4.IconUrl | undefined;
49
+ parseElementStyle(elementProps: Array<ast.ElementProperty> | ast.ElementStyleProperty | undefined): import("../../ast").ParsedElementStyle;
50
+ parseStyleProps(styleProps: Array<ast.StyleProperty> | undefined): import("../../ast").ParsedElementStyle;
27
51
  };
28
52
  } & TBase;
@@ -1,39 +1,15 @@
1
- import { isNonEmptyArray, LinkedList, nonexhaustive, nonNullable } from "@likec4/core";
1
+ import { invariant, isNonEmptyArray, LinkedList, nonexhaustive, nonNullable } from "@likec4/core";
2
+ import { FqnRef } from "@likec4/core/types";
2
3
  import { loggable } from "@likec4/log";
3
4
  import { filter, first, isDefined, isEmpty, isNonNullish, isTruthy, map, mapToObj, pipe } from "remeda";
4
5
  import {
5
6
  ast,
6
- toElementStyle,
7
7
  toRelationshipStyleExcludeDefaults
8
8
  } from "../../ast.js";
9
9
  import { logger as mainLogger } from "../../logger.js";
10
- import { elementRef } from "../../utils/elementRef.js";
11
10
  import { stringHash } from "../../utils/stringHash.js";
12
11
  import { removeIndent, toSingleLine } from "./Base.js";
13
12
  const logger = mainLogger.getChild("ModelParser");
14
- function resolveRelationPoints(node) {
15
- const target = elementRef(node.target);
16
- if (!target) {
17
- throw new Error("RelationRefError: Invalid reference to target");
18
- }
19
- if (isDefined(node.source)) {
20
- const source = elementRef(node.source);
21
- if (!source) {
22
- throw new Error("RelationRefError: Invalid reference to source");
23
- }
24
- return {
25
- source,
26
- target
27
- };
28
- }
29
- if (!ast.isElementBody(node.$container)) {
30
- throw new Error("RelationRefError: Invalid container for sourceless relation");
31
- }
32
- return {
33
- source: node.$container.$container,
34
- target
35
- };
36
- }
37
13
  function* streamModel(doc) {
38
14
  const traverseStack = LinkedList.from(doc.parseResult.value.models.flatMap((m) => m.elements));
39
15
  const relations = [];
@@ -97,8 +73,7 @@ ${error}`, {
97
73
  const id = this.resolveFqn(astNode);
98
74
  const kind = nonNullable(astNode.kind.ref, "Element kind is not resolved").name;
99
75
  const tags = this.parseTags(astNode.body);
100
- const stylePropsAst = astNode.body?.props.find(ast.isElementStyleProperty)?.props;
101
- const style = toElementStyle(stylePropsAst, isValid);
76
+ const style = this.parseElementStyle(astNode.body?.props);
102
77
  const metadata = this.getMetadata(astNode.body?.props.find(ast.isMetadataProperty));
103
78
  const astPath = this.getAstNodePath(astNode);
104
79
  let [title, description, technology] = astNode.props ?? [];
@@ -112,13 +87,6 @@ ${error}`, {
112
87
  description = removeIndent(bodyProps.description ?? description);
113
88
  technology = toSingleLine(bodyProps.technology ?? technology);
114
89
  const links = this.parseLinks(astNode.body);
115
- const iconProp = astNode.body?.props.find(ast.isIconProperty);
116
- if (iconProp && isValid(iconProp)) {
117
- const value = iconProp.libicon?.ref?.name ?? iconProp.value;
118
- if (isTruthy(value)) {
119
- style.icon = value;
120
- }
121
- }
122
90
  return {
123
91
  id,
124
92
  kind,
@@ -133,7 +101,6 @@ ${error}`, {
133
101
  };
134
102
  }
135
103
  parseExtendElement(astNode) {
136
- const isValid = this.isValid;
137
104
  const id = this.resolveFqn(astNode);
138
105
  const tags = this.parseTags(astNode.body);
139
106
  const metadata = this.getMetadata(astNode.body?.props.find(ast.isMetadataProperty));
@@ -150,11 +117,24 @@ ${error}`, {
150
117
  ...links && isNonEmptyArray(links) && { links }
151
118
  };
152
119
  }
120
+ _resolveRelationSource(node) {
121
+ if (isDefined(node.source)) {
122
+ const source = this.parseFqnRef(node.source);
123
+ invariant(FqnRef.isModelRef(source) || FqnRef.isImportRef(source), "Relation source must be a model reference");
124
+ return source;
125
+ }
126
+ if (!ast.isElementBody(node.$container)) {
127
+ throw new Error("RelationRefError: Invalid container for sourceless relation");
128
+ }
129
+ return {
130
+ model: this.resolveFqn(node.$container.$container)
131
+ };
132
+ }
153
133
  parseRelation(astNode) {
154
134
  const isValid = this.isValid;
155
- const coupling = resolveRelationPoints(astNode);
156
- const target = this.resolveFqn(coupling.target);
157
- const source = this.resolveFqn(coupling.source);
135
+ const source = this._resolveRelationSource(astNode);
136
+ const target = this.parseFqnRef(astNode.target);
137
+ invariant(FqnRef.isModelRef(target) || FqnRef.isImportRef(target), "Target must be a model reference");
158
138
  const tags = this.parseTags(astNode) ?? this.parseTags(astNode.body);
159
139
  const links = this.parseLinks(astNode.body);
160
140
  const kind = astNode.kind?.ref?.name;
@@ -177,8 +157,8 @@ ${error}`, {
177
157
  const styleProp = astNode.body?.props.find(ast.isRelationStyleProperty);
178
158
  const id = stringHash(
179
159
  astPath,
180
- source,
181
- target
160
+ source.model,
161
+ target.model
182
162
  );
183
163
  return {
184
164
  id,