@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
@@ -1,6 +1,9 @@
1
1
  import { type GrammarAST, type MaybePromise } from 'langium';
2
2
  import { type CompletionAcceptor, type CompletionContext, DefaultCompletionProvider } from 'langium/lsp';
3
+ import type { LikeC4Services } from '../module';
3
4
  export declare class LikeC4CompletionProvider extends DefaultCompletionProvider {
5
+ protected services: LikeC4Services;
6
+ constructor(services: LikeC4Services);
4
7
  readonly completionOptions: CompletionProviderOptions;
5
8
  protected completionForKeyword(context: CompletionContext, keyword: GrammarAST.Keyword, acceptor: CompletionAcceptor): MaybePromise<void>;
6
9
  }
@@ -17,6 +17,10 @@ const STYLE_FIELDS = [
17
17
  "textSize"
18
18
  ].join(",");
19
19
  export class LikeC4CompletionProvider extends DefaultCompletionProvider {
20
+ constructor(services) {
21
+ super(services);
22
+ this.services = services;
23
+ }
20
24
  completionOptions = {
21
25
  triggerCharacters: ["."]
22
26
  };
@@ -24,87 +28,95 @@ export class LikeC4CompletionProvider extends DefaultCompletionProvider {
24
28
  if (!this.filterKeyword(context, keyword)) {
25
29
  return;
26
30
  }
27
- if (keyword.value === "deployment" && AstUtils.hasContainerOfType(context.node, ast.isModelViews)) {
28
- return acceptor(context, {
29
- label: keyword.value,
30
- detail: `Insert deployment view`,
31
- kind: CompletionItemKind.Class,
32
- insertTextFormat: InsertTextFormat.Snippet,
33
- insertText: [
34
- "deployment view ${1:view_${TM_FILENAME_BASE}_${CURRENT_SECOND}} {",
35
- " title '${2:Untitled}'",
36
- " ",
37
- " include $0",
38
- "}"
39
- ].join("\n")
40
- });
41
- }
42
- if (["title", "description", "technology"].includes(keyword.value)) {
43
- return acceptor(context, {
44
- label: keyword.value,
45
- kind: CompletionItemKind.Property,
46
- insertTextFormat: InsertTextFormat.Snippet,
47
- insertText: `${keyword.value} '\${0}'`
48
- });
49
- }
50
- if (keyword.value === "color") {
51
- return acceptor(context, {
52
- label: keyword.value,
53
- kind: CompletionItemKind.Property,
54
- insertTextFormat: InsertTextFormat.Snippet,
55
- insertText: `${keyword.value} \${1|${ThemeColors.join(",")}|}$0`
56
- });
57
- }
58
- if (keyword.value === "opacity") {
59
- return acceptor(context, {
60
- label: keyword.value,
61
- kind: CompletionItemKind.Property,
62
- insertTextFormat: InsertTextFormat.Snippet,
63
- insertText: `${keyword.value} \${0:100}%`
64
- });
65
- }
66
- if (["views", "specification", "model", "deployment", "with"].includes(keyword.value)) {
67
- return acceptor(context, {
68
- label: keyword.value,
69
- detail: `Insert ${keyword.value} block`,
70
- kind: CompletionItemKind.Module,
71
- insertTextFormat: InsertTextFormat.Snippet,
72
- insertText: `${keyword.value} {
31
+ switch (true) {
32
+ case keyword.value === "import":
33
+ acceptor(context, {
34
+ label: keyword.value,
35
+ kind: CompletionItemKind.Snippet,
36
+ insertTextFormat: InsertTextFormat.Snippet,
37
+ insertText: `${keyword.value} { $0 } from '\${1|${this.services.shared.workspace.ProjectsManager.all.join(",")}|}'`
38
+ });
39
+ break;
40
+ case (keyword.value === "deployment" && AstUtils.hasContainerOfType(context.node, ast.isModelViews)):
41
+ acceptor(context, {
42
+ label: keyword.value,
43
+ detail: `Insert deployment view`,
44
+ kind: CompletionItemKind.Class,
45
+ insertTextFormat: InsertTextFormat.Snippet,
46
+ insertText: [
47
+ "deployment view ${1:view_${TM_FILENAME_BASE}_${CURRENT_SECOND}} {",
48
+ " title '${2:Untitled}'",
49
+ " ",
50
+ " include $0",
51
+ "}"
52
+ ].join("\n")
53
+ });
54
+ break;
55
+ case ["title", "description", "technology"].includes(keyword.value):
56
+ acceptor(context, {
57
+ label: keyword.value,
58
+ kind: CompletionItemKind.Property,
59
+ insertTextFormat: InsertTextFormat.Snippet,
60
+ insertText: `${keyword.value} '\${0}'`
61
+ });
62
+ break;
63
+ case keyword.value === "color":
64
+ acceptor(context, {
65
+ label: keyword.value,
66
+ kind: CompletionItemKind.Property,
67
+ insertTextFormat: InsertTextFormat.Snippet,
68
+ insertText: `${keyword.value} \${1|${ThemeColors.join(",")}|}$0`
69
+ });
70
+ break;
71
+ case keyword.value === "opacity":
72
+ acceptor(context, {
73
+ label: keyword.value,
74
+ kind: CompletionItemKind.Property,
75
+ insertTextFormat: InsertTextFormat.Snippet,
76
+ insertText: `${keyword.value} \${0:100}%`
77
+ });
78
+ break;
79
+ case ["views", "specification", "model", "deployment", "with"].includes(keyword.value):
80
+ acceptor(context, {
81
+ label: keyword.value,
82
+ detail: `Insert ${keyword.value} block`,
83
+ kind: CompletionItemKind.Module,
84
+ insertTextFormat: InsertTextFormat.Snippet,
85
+ insertText: `${keyword.value} {
73
86
  $0
74
87
  }`
75
- });
76
- }
77
- if (keyword.value === "group") {
78
- return acceptor(context, {
79
- label: keyword.value,
80
- detail: `Insert group block`,
81
- kind: CompletionItemKind.Class,
82
- insertTextFormat: InsertTextFormat.Snippet,
83
- insertText: [
84
- "group '${1:Title}' {",
85
- " $0",
86
- "}"
87
- ].join("\n")
88
- });
89
- }
90
- if (keyword.value === "dynamic" && AstUtils.hasContainerOfType(context.node, ast.isModelViews)) {
91
- return acceptor(context, {
92
- label: keyword.value,
93
- detail: `Insert dynamic view`,
94
- kind: CompletionItemKind.Class,
95
- insertTextFormat: InsertTextFormat.Snippet,
96
- insertText: [
97
- "dynamic view ${1:view_${TM_FILENAME_BASE}_${CURRENT_SECOND}} {",
98
- " title '${2:Untitled}'",
99
- " ",
100
- " $0",
101
- "}"
102
- ].join("\n")
103
- });
104
- }
105
- if (keyword.value === "style" && context.node) {
106
- if (AstUtils.hasContainerOfType(context.node, ast.isGlobalStyle)) {
107
- return acceptor(context, {
88
+ });
89
+ break;
90
+ case keyword.value === "group":
91
+ acceptor(context, {
92
+ label: keyword.value,
93
+ detail: `Insert group block`,
94
+ kind: CompletionItemKind.Class,
95
+ insertTextFormat: InsertTextFormat.Snippet,
96
+ insertText: [
97
+ "group '${1:Title}' {",
98
+ " $0",
99
+ "}"
100
+ ].join("\n")
101
+ });
102
+ break;
103
+ case (keyword.value === "dynamic" && AstUtils.hasContainerOfType(context.node, ast.isModelViews)):
104
+ acceptor(context, {
105
+ label: keyword.value,
106
+ detail: `Insert dynamic view`,
107
+ kind: CompletionItemKind.Class,
108
+ insertTextFormat: InsertTextFormat.Snippet,
109
+ insertText: [
110
+ "dynamic view ${1:view_${TM_FILENAME_BASE}_${CURRENT_SECOND}} {",
111
+ " title '${2:Untitled}'",
112
+ " ",
113
+ " $0",
114
+ "}"
115
+ ].join("\n")
116
+ });
117
+ break;
118
+ case (keyword.value === "style" && context.node && AstUtils.hasContainerOfType(context.node, ast.isGlobalStyle)):
119
+ acceptor(context, {
108
120
  label: keyword.value,
109
121
  detail: `Insert ${keyword.value} block`,
110
122
  kind: CompletionItemKind.Module,
@@ -113,9 +125,9 @@ export class LikeC4CompletionProvider extends DefaultCompletionProvider {
113
125
  \${3|${STYLE_FIELDS}|} $0
114
126
  }`
115
127
  });
116
- }
117
- if (AstUtils.hasContainerOfType(context.node, anyPass([ast.isModelViews, ast.isGlobalStyleGroup]))) {
118
- return acceptor(context, {
128
+ break;
129
+ case (keyword.value === "style" && context.node && AstUtils.hasContainerOfType(context.node, anyPass([ast.isModelViews, ast.isGlobalStyleGroup]))):
130
+ acceptor(context, {
119
131
  label: keyword.value,
120
132
  detail: `Insert ${keyword.value} block`,
121
133
  kind: CompletionItemKind.Module,
@@ -124,39 +136,42 @@ export class LikeC4CompletionProvider extends DefaultCompletionProvider {
124
136
  \${2|${STYLE_FIELDS}|} $0
125
137
  }`
126
138
  });
127
- }
128
- return acceptor(context, {
129
- label: keyword.value,
130
- detail: `Insert ${keyword.value} block`,
131
- kind: CompletionItemKind.Module,
132
- insertTextFormat: InsertTextFormat.Snippet,
133
- insertText: `${keyword.value} {
139
+ break;
140
+ case keyword.value === "style":
141
+ acceptor(context, {
142
+ label: keyword.value,
143
+ detail: `Insert ${keyword.value} block`,
144
+ kind: CompletionItemKind.Module,
145
+ insertTextFormat: InsertTextFormat.Snippet,
146
+ insertText: `${keyword.value} {
134
147
  \${1|${STYLE_FIELDS}|} $0
135
148
  }`
136
- });
137
- }
138
- if (keyword.value === "extend") {
139
- return acceptor(context, {
140
- label: keyword.value,
141
- detail: `Extend another view`,
142
- kind: CompletionItemKind.Class,
143
- insertTextFormat: InsertTextFormat.Snippet,
144
- insertText: "extend $1 {\n $0\n}"
145
- });
146
- }
147
- if (keyword.value === "autoLayout") {
148
- return acceptor(context, {
149
- label: keyword.value,
150
- kind: CompletionItemKind.Class,
151
- insertTextFormat: InsertTextFormat.Snippet,
152
- insertText: "autoLayout ${1|TopBottom,BottomTop,LeftRight,RightLeft|}$0"
153
- });
149
+ });
150
+ break;
151
+ case keyword.value === "extend":
152
+ acceptor(context, {
153
+ label: keyword.value,
154
+ detail: `Extend another view`,
155
+ kind: CompletionItemKind.Class,
156
+ insertTextFormat: InsertTextFormat.Snippet,
157
+ insertText: "extend $1 {\n $0\n}"
158
+ });
159
+ break;
160
+ case keyword.value === "autoLayout":
161
+ acceptor(context, {
162
+ label: keyword.value,
163
+ kind: CompletionItemKind.Class,
164
+ insertTextFormat: InsertTextFormat.Snippet,
165
+ insertText: "autoLayout ${1|TopBottom,BottomTop,LeftRight,RightLeft|}$0"
166
+ });
167
+ break;
168
+ default:
169
+ acceptor(context, {
170
+ label: keyword.value,
171
+ kind: this.getKeywordCompletionItemKind(keyword),
172
+ detail: "Keyword",
173
+ sortText: "1"
174
+ });
154
175
  }
155
- acceptor(context, {
156
- label: keyword.value,
157
- kind: this.getKeywordCompletionItemKind(keyword),
158
- detail: "Keyword",
159
- sortText: "1"
160
- });
161
176
  }
162
177
  }
@@ -1,5 +1,5 @@
1
1
  import { AstUtils, GrammarUtils } from "langium";
2
- import { hasLeadingSlash, hasProtocol, isRelative, withoutBase, withoutLeadingSlash } from "ufo";
2
+ import { hasLeadingSlash, hasProtocol, isRelative, joinRelativeURL, withoutBase, withoutLeadingSlash } from "ufo";
3
3
  import { ast, isLikeC4LangiumDocument } from "../ast.js";
4
4
  import { logWarnError } from "../logger.js";
5
5
  export class LikeC4DocumentLinkProvider {
@@ -30,8 +30,11 @@ export class LikeC4DocumentLinkProvider {
30
30
  if (hasProtocol(link) || hasLeadingSlash(link)) {
31
31
  return link;
32
32
  }
33
- const base = isRelative(link) ? new URL(doc.uri.toString(true)) : this.services.shared.workspace.WorkspaceManager.workspaceURL;
34
- return new URL(link, base).toString();
33
+ if (isRelative(link)) {
34
+ return joinRelativeURL(doc.uri.toString(), "../", link);
35
+ }
36
+ const base = this.services.shared.workspace.ProjectsManager.getProject(doc).folder;
37
+ return joinRelativeURL(base.toString(), link);
35
38
  }
36
39
  relativeLink(doc, link) {
37
40
  if (hasLeadingSlash(link)) {
@@ -1,3 +1,4 @@
1
+ import { FqnRef } from "@likec4/core";
1
2
  import { AstUtils } from "langium";
2
3
  import { AstNodeHoverProvider } from "langium/lsp";
3
4
  import { ast } from "../ast.js";
@@ -36,7 +37,8 @@ export class LikeC4HoverProvider extends AstNodeHoverProvider {
36
37
  if (ast.isDeployedInstance(node)) {
37
38
  const doc = AstUtils.getDocument(node);
38
39
  const instance = this.parser.forDocument(doc).parseDeployedInstance(node);
39
- const el = this.locator.getParsedElement(instance.element);
40
+ const [projectId, fqn] = FqnRef.isImportRef(instance.element) ? [instance.element.project, instance.element.model] : [doc.likec4ProjectId, instance.element.model];
41
+ const el = projectId ? this.locator.getParsedElement(fqn, projectId) : this.locator.getParsedElement(fqn);
40
42
  const lines = [instance.id + " ", `instance of \`${instance.element}\``];
41
43
  if (el) {
42
44
  lines.push(`### ${el.title}`, "element kind `" + el.kind + "` ");
@@ -5,23 +5,9 @@ import { ast } from "../ast.js";
5
5
  export class LikeC4SemanticTokenProvider extends AbstractSemanticTokenProvider {
6
6
  // eslint-disable-next-line @typescript-eslint/no-invalid-void-type
7
7
  highlightElement(node, acceptor) {
8
- if (ast.isElement(node) || ast.isDeploymentNode(node)) {
8
+ if (ast.isElement(node) || ast.isDeploymentNode(node) || ast.isDeployedInstance(node)) {
9
9
  return this.highlightNameAndKind(node, acceptor);
10
10
  }
11
- if (ast.isDeployedInstance(node)) {
12
- if ("name" in node) {
13
- acceptor({
14
- node,
15
- property: "name",
16
- type: SemanticTokenTypes.variable,
17
- modifier: [
18
- SemanticTokenModifiers.definition,
19
- SemanticTokenModifiers.readonly
20
- ]
21
- });
22
- }
23
- return;
24
- }
25
11
  if (ast.isLikeC4View(node)) {
26
12
  return this.highlightView(node, acceptor);
27
13
  }
@@ -41,15 +27,7 @@ export class LikeC4SemanticTokenProvider extends AbstractSemanticTokenProvider {
41
27
  });
42
28
  return "prune";
43
29
  }
44
- if (ast.isOutgoingRelationExpression(node) && "kind" in node) {
45
- acceptor({
46
- node,
47
- property: "kind",
48
- type: SemanticTokenTypes.function
49
- });
50
- return;
51
- }
52
- if (ast.isRelation(node) && "kind" in node) {
30
+ if (ast.isRelation(node) || ast.isOutgoingRelationExpr(node) && "kind" in node) {
53
31
  acceptor({
54
32
  node,
55
33
  property: "kind",
@@ -73,7 +51,7 @@ export class LikeC4SemanticTokenProvider extends AbstractSemanticTokenProvider {
73
51
  });
74
52
  return "prune";
75
53
  }
76
- if ((ast.isElementDescedantsExpression(node) || ast.isWildcardExpression(node)) && node.$cstNode) {
54
+ if (ast.isFqnRefExpr(node) || ast.isWildcardExpression(node)) {
77
55
  acceptor({
78
56
  cst: node.$cstNode,
79
57
  type: SemanticTokenTypes.variable,
@@ -82,10 +60,7 @@ export class LikeC4SemanticTokenProvider extends AbstractSemanticTokenProvider {
82
60
  SemanticTokenModifiers.readonly
83
61
  ]
84
62
  });
85
- return "prune";
86
- }
87
- if (ast.isFqnRefExpr(node)) {
88
- if (node.selector) {
63
+ if (ast.isFqnRefExpr(node) && node.selector) {
89
64
  acceptor({
90
65
  node,
91
66
  property: "selector",
@@ -96,7 +71,7 @@ export class LikeC4SemanticTokenProvider extends AbstractSemanticTokenProvider {
96
71
  ]
97
72
  });
98
73
  }
99
- return;
74
+ return "prune";
100
75
  }
101
76
  if (ast.isWhereRelationKind(node) && isTruthy(node.value)) {
102
77
  acceptor({
@@ -195,7 +170,7 @@ export class LikeC4SemanticTokenProvider extends AbstractSemanticTokenProvider {
195
170
  acceptor({
196
171
  node,
197
172
  property: "value",
198
- type: node.parent ? SemanticTokenTypes.property : SemanticTokenTypes.variable,
173
+ type: SemanticTokenTypes.variable,
199
174
  modifier: [
200
175
  SemanticTokenModifiers.definition,
201
176
  SemanticTokenModifiers.readonly
@@ -203,11 +178,11 @@ export class LikeC4SemanticTokenProvider extends AbstractSemanticTokenProvider {
203
178
  });
204
179
  return !node.parent ? "prune" : void 0;
205
180
  }
206
- if (ast.isElementRef(node) || ast.isStrictFqnElementRef(node)) {
181
+ if (ast.isStrictFqnElementRef(node)) {
207
182
  acceptor({
208
183
  node,
209
184
  property: "el",
210
- type: node.parent ? SemanticTokenTypes.property : SemanticTokenTypes.variable,
185
+ type: SemanticTokenTypes.variable,
211
186
  modifier: [
212
187
  SemanticTokenModifiers.definition,
213
188
  SemanticTokenModifiers.readonly
@@ -215,6 +190,18 @@ export class LikeC4SemanticTokenProvider extends AbstractSemanticTokenProvider {
215
190
  });
216
191
  return !node.parent ? "prune" : void 0;
217
192
  }
193
+ if (ast.isImported(node)) {
194
+ acceptor({
195
+ node,
196
+ property: "imported",
197
+ type: SemanticTokenTypes.variable,
198
+ modifier: [
199
+ SemanticTokenModifiers.definition,
200
+ SemanticTokenModifiers.readonly
201
+ ]
202
+ });
203
+ return "prune";
204
+ }
218
205
  if (ast.isSpecificationColor(node)) {
219
206
  acceptor({
220
207
  node,
@@ -244,11 +231,12 @@ export class LikeC4SemanticTokenProvider extends AbstractSemanticTokenProvider {
244
231
  });
245
232
  }
246
233
  if (ast.isTags(node)) {
247
- return acceptor({
234
+ acceptor({
248
235
  node,
249
236
  property: "values",
250
237
  type: SemanticTokenTypes.interface
251
238
  });
239
+ return "prune";
252
240
  }
253
241
  if (ast.isTag(node)) {
254
242
  return acceptor({
@@ -258,7 +246,7 @@ export class LikeC4SemanticTokenProvider extends AbstractSemanticTokenProvider {
258
246
  modifier: [SemanticTokenModifiers.definition]
259
247
  });
260
248
  }
261
- if (ast.isRelationStyleProperty(node) || ast.isElementStyleProperty(node) && ast.isElementBody(node.$container)) {
249
+ if (ast.isRelationStyleProperty(node) || ast.isElementStyleProperty(node)) {
262
250
  acceptor({
263
251
  node,
264
252
  property: "key",
@@ -322,18 +310,20 @@ export class LikeC4SemanticTokenProvider extends AbstractSemanticTokenProvider {
322
310
  acceptor({
323
311
  node,
324
312
  property: "name",
325
- type: SemanticTokenTypes.variable,
313
+ type: SemanticTokenTypes.function,
326
314
  modifier: [
327
315
  SemanticTokenModifiers.declaration,
328
316
  SemanticTokenModifiers.readonly
329
317
  ]
330
318
  });
331
- acceptor({
332
- node,
333
- property: "kind",
334
- type: SemanticTokenTypes.keyword,
335
- modifier: []
336
- });
319
+ if (!ast.isDeployedInstance(node)) {
320
+ acceptor({
321
+ node,
322
+ property: "kind",
323
+ type: SemanticTokenTypes.keyword,
324
+ modifier: []
325
+ });
326
+ }
337
327
  if (ast.isElement(node)) {
338
328
  if (node.props.length > 0) {
339
329
  acceptor({
@@ -357,7 +347,7 @@ export class LikeC4SemanticTokenProvider extends AbstractSemanticTokenProvider {
357
347
  acceptor({
358
348
  node,
359
349
  property: "name",
360
- type: SemanticTokenTypes.variable,
350
+ type: SemanticTokenTypes.interface,
361
351
  modifier: [
362
352
  SemanticTokenModifiers.declaration,
363
353
  SemanticTokenModifiers.readonly,
@@ -1,5 +1,6 @@
1
1
  import type * as c4 from '@likec4/core';
2
- import type { ParsedAstDeploymentRelation, ParsedAstElement, ParsedAstRelation, ParsedAstSpecification, ParsedLikeC4LangiumDocument } from '../../ast';
2
+ import { MultiMap } from '@likec4/core';
3
+ import type { ParsedAstDeployment, ParsedAstDeploymentRelation, ParsedAstElement, ParsedAstRelation, ParsedAstSpecification, ParsedLikeC4LangiumDocument } from '../../ast';
3
4
  /**
4
5
  * The `MergedSpecification` class is responsible for merging multiple parsed
5
6
  * LikeC4Langium documents into a single specification. It consolidates tags,
@@ -9,6 +10,7 @@ import type { ParsedAstDeploymentRelation, ParsedAstElement, ParsedAstRelation,
9
10
  export declare class MergedSpecification {
10
11
  readonly specs: ParsedAstSpecification;
11
12
  readonly globals: c4.ModelGlobals;
13
+ readonly imports: MultiMap<c4.ProjectId, c4.Fqn, Set<c4.Fqn>>;
12
14
  constructor(docs: ParsedLikeC4LangiumDocument[]);
13
15
  /**
14
16
  * Converts a parsed model into a C4 model element.
@@ -17,11 +19,11 @@ export declare class MergedSpecification {
17
19
  /**
18
20
  * Converts a parsed model into a C4 model relation.
19
21
  */
20
- toModelRelation: ({ astPath, source, target, kind, links, id, ...model }: ParsedAstRelation) => c4.ModelRelation | null;
22
+ toModelRelation: ({ astPath, source: sourceFqnRef, target: targetFqnRef, kind, links, id, ...model }: ParsedAstRelation) => c4.ModelRelation | null;
21
23
  /**
22
24
  * Converts a parsed deployment model into a C4 deployment model
23
25
  */
24
- toDeploymentElement: (parsed: c4.DeploymentElement) => c4.DeploymentElement | null;
26
+ toDeploymentElement: (parsed: ParsedAstDeployment) => c4.DeploymentElement | null;
25
27
  /**
26
28
  * Converts a parsed deployment relation into a C4 deployment relation.
27
29
  */
@@ -1,6 +1,7 @@
1
+ import { MultiMap } from "@likec4/core";
1
2
  import {
2
- DeploymentElement
3
- } from "@likec4/core";
3
+ FqnRef
4
+ } from "@likec4/core/types";
4
5
  import {
5
6
  isBoolean,
6
7
  isEmpty,
@@ -21,11 +22,13 @@ export class MergedSpecification {
21
22
  dynamicPredicates: {},
22
23
  styles: {}
23
24
  };
25
+ imports = new MultiMap(Set);
24
26
  constructor(docs) {
25
27
  for (const doc of docs) {
26
28
  const {
27
29
  c4Specification: spec,
28
- c4Globals
30
+ c4Globals,
31
+ c4Imports
29
32
  } = doc;
30
33
  spec.tags.forEach((t) => this.specs.tags.add(t));
31
34
  Object.assign(this.specs.elements, spec.elements);
@@ -35,6 +38,9 @@ export class MergedSpecification {
35
38
  Object.assign(this.globals.predicates, c4Globals.predicates);
36
39
  Object.assign(this.globals.dynamicPredicates, c4Globals.dynamicPredicates);
37
40
  Object.assign(this.globals.styles, c4Globals.styles);
41
+ for (const [projectId, fqn] of c4Imports) {
42
+ this.imports.set(projectId, fqn);
43
+ }
38
44
  }
39
45
  }
40
46
  /**
@@ -109,13 +115,15 @@ export class MergedSpecification {
109
115
  */
110
116
  toModelRelation = ({
111
117
  astPath,
112
- source,
113
- target,
118
+ source: sourceFqnRef,
119
+ target: targetFqnRef,
114
120
  kind,
115
121
  links,
116
122
  id,
117
123
  ...model
118
124
  }) => {
125
+ const target = FqnRef.toModelFqn(targetFqnRef);
126
+ const source = FqnRef.toModelFqn(sourceFqnRef);
119
127
  if (isNonNullish(kind) && this.specs.relationships[kind]) {
120
128
  return {
121
129
  ...this.specs.relationships[kind],
@@ -139,8 +147,14 @@ export class MergedSpecification {
139
147
  * Converts a parsed deployment model into a C4 deployment model
140
148
  */
141
149
  toDeploymentElement = (parsed) => {
142
- if (!DeploymentElement.isDeploymentNode(parsed)) {
143
- return parsed;
150
+ if ("element" in parsed && !("kind" in parsed)) {
151
+ return {
152
+ ...parsed,
153
+ element: FqnRef.toModelFqn(parsed.element)
154
+ };
155
+ }
156
+ if ("element" in parsed) {
157
+ return null;
144
158
  }
145
159
  try {
146
160
  const __kind = this.specs.deployments[parsed.kind];
@@ -1,5 +1,10 @@
1
1
  import type * as c4 from '@likec4/core';
2
+ import { type MultiMap } from '@likec4/core';
2
3
  import type { ParsedLikeC4LangiumDocument } from '../../ast';
4
+ export type BuildModelData = {
5
+ data: c4.ParsedLikeC4ModelData;
6
+ imports: MultiMap<c4.ProjectId, c4.Fqn, Set<c4.Fqn>>;
7
+ };
3
8
  /**
4
9
  * Each document was parsed into a ParsedLikeC4LangiumDocument, where elements
5
10
  * do not inherit styles from specification.
@@ -7,4 +12,4 @@ import type { ParsedLikeC4LangiumDocument } from '../../ast';
7
12
  * This function builds a model from all documents, merging the specifications
8
13
  * and globals, and applying the extends to the elements.
9
14
  */
10
- export declare function buildModel(docs: ParsedLikeC4LangiumDocument[]): c4.ParsedLikeC4ModelData;
15
+ export declare function buildModelData(docs: ParsedLikeC4LangiumDocument[]): BuildModelData;