@likec4/language-server 0.37.1 → 0.41.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.
- package/contrib/likec4.monarch.ts +5 -5
- package/contrib/likec4.tmLanguage.json +1 -1
- package/dist/Rpc.d.ts +7 -0
- package/dist/Rpc.js +130 -0
- package/dist/ast.d.ts +20 -0
- package/dist/ast.js +169 -141
- package/dist/elementRef.js +31 -44
- package/dist/generated/ast.d.ts +48 -7
- package/dist/generated/ast.js +344 -315
- package/dist/generated/grammar.js +2 -3177
- package/dist/generated/module.js +13 -18
- package/dist/index.js +2 -3
- package/dist/logger.js +39 -42
- package/dist/lsp/CodeLensProvider.js +28 -32
- package/dist/lsp/DocumentLinkProvider.js +26 -33
- package/dist/lsp/DocumentSymbolProvider.js +165 -167
- package/dist/lsp/HoverProvider.js +35 -48
- package/dist/lsp/SemanticTokenProvider.js +160 -201
- package/dist/lsp/index.js +5 -6
- package/dist/model/fqn-computation.js +39 -40
- package/dist/model/fqn-index.js +117 -141
- package/dist/model/index.js +5 -6
- package/dist/model/model-builder.d.ts +10 -5
- package/dist/model/model-builder.js +247 -176
- package/dist/model/model-locator.d.ts +1 -1
- package/dist/model/model-locator.js +102 -100
- package/dist/model/model-parser.d.ts +2 -6
- package/dist/model/model-parser.js +284 -286
- package/dist/module.d.ts +4 -1
- package/dist/module.js +69 -60
- package/dist/protocol.d.ts +16 -19
- package/dist/protocol.js +14 -22
- package/dist/references/index.js +2 -3
- package/dist/references/scope-computation.js +72 -69
- package/dist/references/scope-provider.js +126 -116
- package/dist/shared/WorkspaceManager.d.ts +2 -3
- package/dist/shared/WorkspaceManager.js +13 -16
- package/dist/shared/index.js +1 -2
- package/dist/test/index.js +1 -2
- package/dist/test/testServices.js +73 -61
- package/dist/utils.d.ts +1 -0
- package/dist/utils.js +4 -3
- package/dist/validation/element.d.ts +1 -0
- package/dist/validation/element.js +31 -38
- package/dist/validation/index.js +37 -46
- package/dist/validation/relation.js +46 -46
- package/dist/validation/specification.d.ts +1 -0
- package/dist/validation/specification.js +33 -30
- package/dist/validation/view.js +16 -22
- package/dist/view-utils/assignNavigateTo.d.ts +3 -0
- package/dist/view-utils/assignNavigateTo.js +20 -0
- package/dist/view-utils/index.d.ts +4 -0
- package/dist/view-utils/index.js +3 -0
- package/dist/view-utils/resolve-extended-views.d.ts +7 -0
- package/dist/view-utils/resolve-extended-views.js +41 -0
- package/dist/view-utils/resolve-relative-paths.d.ts +3 -0
- package/dist/view-utils/resolve-relative-paths.js +76 -0
- package/package.json +33 -18
- package/dist/registerProtocolHandlers.d.ts +0 -3
- package/dist/registerProtocolHandlers.js +0 -112
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import { type c4 } from '@likec4/core';
|
|
2
2
|
import type { LangiumDocument } from 'langium';
|
|
3
|
-
import { Disposable, type CancellationToken } from 'vscode-languageserver-protocol';
|
|
4
3
|
import type { LikeC4LangiumDocument } from '../ast';
|
|
5
4
|
import { ast } from '../ast';
|
|
6
5
|
import type { LikeC4Services } from '../module';
|
|
@@ -8,11 +7,9 @@ export type ModelParsedListener = () => void;
|
|
|
8
7
|
export declare class LikeC4ModelParser {
|
|
9
8
|
private services;
|
|
10
9
|
private fqnIndex;
|
|
11
|
-
protected readonly listeners: ModelParsedListener[];
|
|
12
10
|
constructor(services: LikeC4Services);
|
|
13
|
-
|
|
14
|
-
protected
|
|
15
|
-
protected parseDocument(doc: LikeC4LangiumDocument, cancelToken: CancellationToken): Promise<void>;
|
|
11
|
+
parse(doc: LangiumDocument | LangiumDocument[]): void;
|
|
12
|
+
protected parseLikeC4Document(doc: LikeC4LangiumDocument): void;
|
|
16
13
|
private parseElement;
|
|
17
14
|
private parseRelation;
|
|
18
15
|
private parseElementExpression;
|
|
@@ -22,6 +19,5 @@ export declare class LikeC4ModelParser {
|
|
|
22
19
|
protected resolveFqn(node: ast.Element | ast.ExtendElement): c4.Fqn;
|
|
23
20
|
private getAstNodePath;
|
|
24
21
|
private convertTags;
|
|
25
|
-
private notifyListeners;
|
|
26
22
|
}
|
|
27
23
|
//# sourceMappingURL=model-parser.d.ts.map
|
|
@@ -1,309 +1,307 @@
|
|
|
1
|
-
import { InvalidModelError, invariant, isNonEmptyArray, nonexhaustive } from
|
|
2
|
-
import {
|
|
3
|
-
import objectHash from
|
|
4
|
-
import stripIndent from
|
|
5
|
-
import {
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
1
|
+
import { InvalidModelError, invariant, isNonEmptyArray, nonexhaustive } from "@likec4/core";
|
|
2
|
+
import { getDocument } from "langium";
|
|
3
|
+
import objectHash from "object-hash";
|
|
4
|
+
import stripIndent from "strip-indent";
|
|
5
|
+
import {
|
|
6
|
+
ElementViewOps,
|
|
7
|
+
ast,
|
|
8
|
+
cleanParsedModel,
|
|
9
|
+
isLikeC4LangiumDocument,
|
|
10
|
+
resolveRelationPoints,
|
|
11
|
+
streamModel,
|
|
12
|
+
toAutoLayout,
|
|
13
|
+
toElementStyle,
|
|
14
|
+
toElementStyleExcludeDefaults,
|
|
15
|
+
toRelationshipStyleExcludeDefaults
|
|
16
|
+
} from "../ast.js";
|
|
17
|
+
import { elementRef, fqnElementRef } from "../elementRef.js";
|
|
18
|
+
import { logError, logWarnError, logger } from "../logger.js";
|
|
19
|
+
import { printDocs } from "../utils.js";
|
|
10
20
|
export class LikeC4ModelParser {
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
21
|
+
constructor(services) {
|
|
22
|
+
this.services = services;
|
|
23
|
+
this.fqnIndex = services.likec4.FqnIndex;
|
|
24
|
+
}
|
|
25
|
+
fqnIndex;
|
|
26
|
+
parse(doc) {
|
|
27
|
+
const docs = Array.isArray(doc) ? doc : [doc];
|
|
28
|
+
logger.debug(`[ModelParser] onValidated (${docs.length} docs)
|
|
29
|
+
${printDocs(docs)}`);
|
|
30
|
+
for (const doc2 of docs) {
|
|
31
|
+
if (!isLikeC4LangiumDocument(doc2)) {
|
|
32
|
+
continue;
|
|
33
|
+
}
|
|
34
|
+
try {
|
|
35
|
+
this.parseLikeC4Document(doc2);
|
|
36
|
+
} catch (cause) {
|
|
37
|
+
logError(new InvalidModelError(`Error parsing document ${doc2.uri.toString()}`, { cause }));
|
|
38
|
+
}
|
|
18
39
|
}
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
40
|
+
}
|
|
41
|
+
parseLikeC4Document(doc) {
|
|
42
|
+
const { elements, relations, views, specification } = cleanParsedModel(doc);
|
|
43
|
+
const specs = doc.parseResult.value.specification?.elements;
|
|
44
|
+
if (specs) {
|
|
45
|
+
for (const { kind, style } of specs) {
|
|
46
|
+
if (kind.name in specification.kinds) {
|
|
47
|
+
logger.warn(`Duplicate specification for kind ${kind.name}`);
|
|
48
|
+
continue;
|
|
49
|
+
}
|
|
50
|
+
try {
|
|
51
|
+
specification.kinds[kind.name] = toElementStyleExcludeDefaults(
|
|
52
|
+
style?.props
|
|
53
|
+
);
|
|
54
|
+
} catch (e) {
|
|
55
|
+
logWarnError(e);
|
|
56
|
+
}
|
|
57
|
+
}
|
|
27
58
|
}
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
}
|
|
35
|
-
countOfChangedDocs++;
|
|
36
|
-
try {
|
|
37
|
-
await this.parseDocument(doc, cancelToken);
|
|
38
|
-
}
|
|
39
|
-
catch (cause) {
|
|
40
|
-
logError(new InvalidModelError(`Error parsing document ${doc.uri.toString()}`, { cause }));
|
|
41
|
-
}
|
|
59
|
+
const relations_specs = doc.parseResult.value.specification?.relationships;
|
|
60
|
+
if (relations_specs) {
|
|
61
|
+
for (const { kind, props } of relations_specs) {
|
|
62
|
+
if (kind.name in specification.relationships) {
|
|
63
|
+
logger.warn(`Duplicate specification for kind ${kind.name}`);
|
|
64
|
+
continue;
|
|
42
65
|
}
|
|
43
|
-
|
|
44
|
-
|
|
66
|
+
try {
|
|
67
|
+
specification.relationships[kind.name] = toRelationshipStyleExcludeDefaults(
|
|
68
|
+
props
|
|
69
|
+
);
|
|
70
|
+
} catch (e) {
|
|
71
|
+
logWarnError(e);
|
|
45
72
|
}
|
|
73
|
+
}
|
|
46
74
|
}
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
logger.warn(`Duplicate specification for kind ${kind.name}`);
|
|
54
|
-
continue;
|
|
55
|
-
}
|
|
56
|
-
try {
|
|
57
|
-
specification.kinds[kind.name] = toElementStyleExcludeDefaults(style?.props);
|
|
58
|
-
}
|
|
59
|
-
catch (e) {
|
|
60
|
-
logWarnError(e);
|
|
61
|
-
}
|
|
62
|
-
}
|
|
75
|
+
for (const el of streamModel(doc)) {
|
|
76
|
+
if (ast.isElement(el)) {
|
|
77
|
+
try {
|
|
78
|
+
elements.push(this.parseElement(el));
|
|
79
|
+
} catch (e) {
|
|
80
|
+
logWarnError(e);
|
|
63
81
|
}
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
logWarnError(e);
|
|
72
|
-
}
|
|
73
|
-
continue;
|
|
74
|
-
}
|
|
75
|
-
if (ast.isRelation(el)) {
|
|
76
|
-
try {
|
|
77
|
-
relations.push(this.parseRelation(el));
|
|
78
|
-
}
|
|
79
|
-
catch (e) {
|
|
80
|
-
logWarnError(e);
|
|
81
|
-
}
|
|
82
|
-
continue;
|
|
83
|
-
}
|
|
84
|
-
nonexhaustive(el);
|
|
82
|
+
continue;
|
|
83
|
+
}
|
|
84
|
+
if (ast.isRelation(el)) {
|
|
85
|
+
try {
|
|
86
|
+
relations.push(this.parseRelation(el));
|
|
87
|
+
} catch (e) {
|
|
88
|
+
logWarnError(e);
|
|
85
89
|
}
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
90
|
+
continue;
|
|
91
|
+
}
|
|
92
|
+
nonexhaustive(el);
|
|
93
|
+
}
|
|
94
|
+
const docviews = doc.parseResult.value.views?.views;
|
|
95
|
+
if (docviews) {
|
|
96
|
+
for (const view of docviews) {
|
|
97
|
+
try {
|
|
98
|
+
const v = this.parseElementView(view);
|
|
99
|
+
ElementViewOps.writeId(view, v.id);
|
|
100
|
+
views.push(v);
|
|
101
|
+
} catch (e) {
|
|
102
|
+
logWarnError(e);
|
|
99
103
|
}
|
|
100
|
-
|
|
101
|
-
// doc.c4hash = c4hash(doc)
|
|
102
|
-
// return prevHash !== doc.c4hash
|
|
104
|
+
}
|
|
103
105
|
}
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
106
|
+
}
|
|
107
|
+
parseElement(astNode) {
|
|
108
|
+
const id = this.resolveFqn(astNode);
|
|
109
|
+
invariant(astNode.kind.ref, "Element kind is not resolved: " + astNode.name);
|
|
110
|
+
const kind = astNode.kind.ref.name;
|
|
111
|
+
const tags = this.convertTags(astNode.body);
|
|
112
|
+
const stylePropsAst = astNode.body?.props.find(ast.isStyleProperties)?.props;
|
|
113
|
+
const styleProps = toElementStyleExcludeDefaults(stylePropsAst);
|
|
114
|
+
const astPath = this.getAstNodePath(astNode);
|
|
115
|
+
let [title, description, technology] = astNode.props;
|
|
116
|
+
const bodyProps = astNode.body?.props.filter(
|
|
117
|
+
(p) => ast.isElementStringProperty(p)
|
|
118
|
+
) ?? [];
|
|
119
|
+
title = title ?? bodyProps.find((p) => p.key === "title")?.value;
|
|
120
|
+
description = description ?? bodyProps.find((p) => p.key === "description")?.value;
|
|
121
|
+
technology = technology ?? bodyProps.find((p) => p.key === "technology")?.value;
|
|
122
|
+
const links = astNode.body?.props.filter(ast.isLinkProperty).map((p) => p.value);
|
|
123
|
+
return {
|
|
124
|
+
id,
|
|
125
|
+
kind,
|
|
126
|
+
astPath,
|
|
127
|
+
title: title ? stripIndent(title).trim() : astNode.name,
|
|
128
|
+
...tags && { tags },
|
|
129
|
+
...links && isNonEmptyArray(links) && { links },
|
|
130
|
+
...technology && { technology },
|
|
131
|
+
...description && { description: stripIndent(description).trim() },
|
|
132
|
+
...styleProps
|
|
133
|
+
};
|
|
134
|
+
}
|
|
135
|
+
parseRelation(astNode) {
|
|
136
|
+
const coupling = resolveRelationPoints(astNode);
|
|
137
|
+
const target = this.resolveFqn(coupling.target);
|
|
138
|
+
const source = this.resolveFqn(coupling.source);
|
|
139
|
+
const kind = astNode.kind?.ref?.name;
|
|
140
|
+
const hashdata = {
|
|
141
|
+
astPath: this.getAstNodePath(astNode),
|
|
142
|
+
source,
|
|
143
|
+
target
|
|
144
|
+
};
|
|
145
|
+
const id = objectHash(hashdata);
|
|
146
|
+
const title = astNode.title ?? astNode.body?.props.find((p) => p.key === "title")?.value ?? "";
|
|
147
|
+
return {
|
|
148
|
+
id,
|
|
149
|
+
...hashdata,
|
|
150
|
+
...kind && { kind },
|
|
151
|
+
title
|
|
152
|
+
};
|
|
153
|
+
}
|
|
154
|
+
parseElementExpression(astNode) {
|
|
155
|
+
if (ast.isWildcardExpression(astNode)) {
|
|
156
|
+
return {
|
|
157
|
+
wildcard: true
|
|
158
|
+
};
|
|
129
159
|
}
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
const id = objectHash(hashdata);
|
|
140
|
-
const title = astNode.title ?? astNode.body?.props.find(p => p.key === 'title')?.value ?? '';
|
|
141
|
-
return {
|
|
142
|
-
id,
|
|
143
|
-
...hashdata,
|
|
144
|
-
title
|
|
145
|
-
};
|
|
160
|
+
if (ast.isElementKindExpression(astNode)) {
|
|
161
|
+
invariant(
|
|
162
|
+
astNode.kind.ref,
|
|
163
|
+
"ElementKindExpression kind is not resolved: " + astNode.$cstNode?.text
|
|
164
|
+
);
|
|
165
|
+
return {
|
|
166
|
+
elementKind: astNode.kind.ref.name,
|
|
167
|
+
isEqual: astNode.isEqual
|
|
168
|
+
};
|
|
146
169
|
}
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
elementKind: astNode.kind.ref.name,
|
|
157
|
-
isEqual: astNode.isEqual
|
|
158
|
-
};
|
|
159
|
-
}
|
|
160
|
-
if (ast.isElementTagExpression(astNode)) {
|
|
161
|
-
invariant(astNode.tag.ref, 'ElementTagExpression tag is not resolved: ' + astNode.$cstNode?.text);
|
|
162
|
-
return {
|
|
163
|
-
elementTag: astNode.tag.ref.name,
|
|
164
|
-
isEqual: astNode.isEqual
|
|
165
|
-
};
|
|
166
|
-
}
|
|
167
|
-
if (ast.isElementRefExpression(astNode)) {
|
|
168
|
-
const element = elementRef(astNode.id);
|
|
169
|
-
invariant(element, 'Element not found ' + astNode.id.$cstNode?.text);
|
|
170
|
-
return {
|
|
171
|
-
element: this.resolveFqn(element),
|
|
172
|
-
isDescedants: astNode.isDescedants
|
|
173
|
-
};
|
|
174
|
-
}
|
|
175
|
-
nonexhaustive(astNode);
|
|
170
|
+
if (ast.isElementTagExpression(astNode)) {
|
|
171
|
+
invariant(
|
|
172
|
+
astNode.tag.ref,
|
|
173
|
+
"ElementTagExpression tag is not resolved: " + astNode.$cstNode?.text
|
|
174
|
+
);
|
|
175
|
+
return {
|
|
176
|
+
elementTag: astNode.tag.ref.name,
|
|
177
|
+
isEqual: astNode.isEqual
|
|
178
|
+
};
|
|
176
179
|
}
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
};
|
|
185
|
-
}
|
|
186
|
-
if (ast.isOutgoingExpression(astNode)) {
|
|
187
|
-
return {
|
|
188
|
-
outgoing: this.parseElementExpression(astNode.source)
|
|
189
|
-
};
|
|
190
|
-
}
|
|
191
|
-
if (ast.isInOutExpression(astNode)) {
|
|
192
|
-
return {
|
|
193
|
-
inout: this.parseElementExpression(astNode.inout.target)
|
|
194
|
-
};
|
|
195
|
-
}
|
|
196
|
-
if (ast.isRelationExpression(astNode)) {
|
|
197
|
-
return {
|
|
198
|
-
source: this.parseElementExpression(astNode.source),
|
|
199
|
-
target: this.parseElementExpression(astNode.target)
|
|
200
|
-
};
|
|
201
|
-
}
|
|
202
|
-
nonexhaustive(astNode);
|
|
180
|
+
if (ast.isElementRefExpression(astNode)) {
|
|
181
|
+
const element = elementRef(astNode.id);
|
|
182
|
+
invariant(element, "Element not found " + astNode.id.$cstNode?.text);
|
|
183
|
+
return {
|
|
184
|
+
element: this.resolveFqn(element),
|
|
185
|
+
isDescedants: astNode.isDescedants
|
|
186
|
+
};
|
|
203
187
|
}
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
exprs
|
|
210
|
-
};
|
|
211
|
-
}
|
|
212
|
-
if (ast.isViewRuleStyle(astRule)) {
|
|
213
|
-
const styleProps = toElementStyle(astRule.props);
|
|
214
|
-
return {
|
|
215
|
-
targets: astRule.targets.map(n => this.parseElementExpression(n)),
|
|
216
|
-
style: {
|
|
217
|
-
...styleProps
|
|
218
|
-
}
|
|
219
|
-
};
|
|
220
|
-
}
|
|
221
|
-
if (ast.isViewRuleAutoLayout(astRule)) {
|
|
222
|
-
return {
|
|
223
|
-
autoLayout: toAutoLayout(astRule.direction)
|
|
224
|
-
};
|
|
225
|
-
}
|
|
226
|
-
nonexhaustive(astRule);
|
|
188
|
+
nonexhaustive(astNode);
|
|
189
|
+
}
|
|
190
|
+
parseExpression(astNode) {
|
|
191
|
+
if (ast.isElementExpression(astNode)) {
|
|
192
|
+
return this.parseElementExpression(astNode);
|
|
227
193
|
}
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
let id = astNode.name;
|
|
233
|
-
if (!id) {
|
|
234
|
-
const doc = getDocument(astNode).uri.toString();
|
|
235
|
-
id = objectHash({
|
|
236
|
-
doc,
|
|
237
|
-
astPath
|
|
238
|
-
});
|
|
239
|
-
}
|
|
240
|
-
const title = body.props.find(p => p.key === 'title')?.value;
|
|
241
|
-
const description = body.props.find(p => p.key === 'description')?.value;
|
|
242
|
-
const tags = this.convertTags(body);
|
|
243
|
-
const links = body.props.filter(ast.isLinkProperty).map(p => p.value);
|
|
244
|
-
const basic = {
|
|
245
|
-
id: id,
|
|
246
|
-
astPath,
|
|
247
|
-
...(title && { title }),
|
|
248
|
-
...(description && { description }),
|
|
249
|
-
...(tags && { tags }),
|
|
250
|
-
...(isNonEmptyArray(links) && { links }),
|
|
251
|
-
rules: body.rules.flatMap(n => {
|
|
252
|
-
try {
|
|
253
|
-
return this.parseViewRule(n);
|
|
254
|
-
}
|
|
255
|
-
catch (e) {
|
|
256
|
-
logWarnError(e);
|
|
257
|
-
return [];
|
|
258
|
-
}
|
|
259
|
-
})
|
|
260
|
-
};
|
|
261
|
-
if ('viewOf' in astNode) {
|
|
262
|
-
const viewOfEl = elementRef(astNode.viewOf);
|
|
263
|
-
const viewOf = viewOfEl && this.resolveFqn(viewOfEl);
|
|
264
|
-
invariant(viewOf, ' viewOf is not resolved: ' + astNode.$cstNode?.text);
|
|
265
|
-
return {
|
|
266
|
-
...basic,
|
|
267
|
-
viewOf
|
|
268
|
-
};
|
|
269
|
-
}
|
|
270
|
-
if ('extends' in astNode) {
|
|
271
|
-
const extendsView = astNode.extends.view.ref;
|
|
272
|
-
invariant(extendsView?.name, 'view extends is not resolved: ' + astNode.$cstNode?.text);
|
|
273
|
-
return {
|
|
274
|
-
...basic,
|
|
275
|
-
extends: extendsView.name
|
|
276
|
-
};
|
|
277
|
-
}
|
|
278
|
-
return basic;
|
|
194
|
+
if (ast.isIncomingExpression(astNode)) {
|
|
195
|
+
return {
|
|
196
|
+
incoming: this.parseElementExpression(astNode.target)
|
|
197
|
+
};
|
|
279
198
|
}
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
199
|
+
if (ast.isOutgoingExpression(astNode)) {
|
|
200
|
+
return {
|
|
201
|
+
outgoing: this.parseElementExpression(astNode.source)
|
|
202
|
+
};
|
|
203
|
+
}
|
|
204
|
+
if (ast.isInOutExpression(astNode)) {
|
|
205
|
+
return {
|
|
206
|
+
inout: this.parseElementExpression(astNode.inout.target)
|
|
207
|
+
};
|
|
287
208
|
}
|
|
288
|
-
|
|
289
|
-
|
|
209
|
+
if (ast.isRelationExpression(astNode)) {
|
|
210
|
+
return {
|
|
211
|
+
source: this.parseElementExpression(astNode.source),
|
|
212
|
+
target: this.parseElementExpression(astNode.target)
|
|
213
|
+
};
|
|
290
214
|
}
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
215
|
+
nonexhaustive(astNode);
|
|
216
|
+
}
|
|
217
|
+
parseViewRule(astRule) {
|
|
218
|
+
if (ast.isViewRuleExpression(astRule)) {
|
|
219
|
+
const exprs = astRule.expressions.map((n) => this.parseExpression(n));
|
|
220
|
+
return astRule.isInclude ? { include: exprs } : { exclude: exprs };
|
|
221
|
+
}
|
|
222
|
+
if (ast.isViewRuleStyle(astRule)) {
|
|
223
|
+
const styleProps = toElementStyle(astRule.props);
|
|
224
|
+
return {
|
|
225
|
+
targets: astRule.targets.map((n) => this.parseElementExpression(n)),
|
|
226
|
+
style: {
|
|
227
|
+
...styleProps
|
|
294
228
|
}
|
|
295
|
-
|
|
296
|
-
|
|
229
|
+
};
|
|
230
|
+
}
|
|
231
|
+
if (ast.isViewRuleAutoLayout(astRule)) {
|
|
232
|
+
return {
|
|
233
|
+
autoLayout: toAutoLayout(astRule.direction)
|
|
234
|
+
};
|
|
235
|
+
}
|
|
236
|
+
nonexhaustive(astRule);
|
|
237
|
+
}
|
|
238
|
+
parseElementView(astNode) {
|
|
239
|
+
const body = astNode.body;
|
|
240
|
+
invariant(body, "ElementView body is not defined");
|
|
241
|
+
const astPath = this.getAstNodePath(astNode);
|
|
242
|
+
let id = astNode.name;
|
|
243
|
+
if (!id) {
|
|
244
|
+
const doc = getDocument(astNode).uri.toString();
|
|
245
|
+
id = objectHash({
|
|
246
|
+
doc,
|
|
247
|
+
astPath
|
|
248
|
+
});
|
|
297
249
|
}
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
250
|
+
const title = body.props.find((p) => p.key === "title")?.value;
|
|
251
|
+
const description = body.props.find((p) => p.key === "description")?.value;
|
|
252
|
+
const tags = this.convertTags(body);
|
|
253
|
+
const links = body.props.filter(ast.isLinkProperty).map((p) => p.value);
|
|
254
|
+
const basic = {
|
|
255
|
+
id,
|
|
256
|
+
astPath,
|
|
257
|
+
...title && { title },
|
|
258
|
+
...description && { description },
|
|
259
|
+
...tags && { tags },
|
|
260
|
+
...isNonEmptyArray(links) && { links },
|
|
261
|
+
rules: body.rules.flatMap((n) => {
|
|
262
|
+
try {
|
|
263
|
+
return this.parseViewRule(n);
|
|
264
|
+
} catch (e) {
|
|
265
|
+
logWarnError(e);
|
|
266
|
+
return [];
|
|
306
267
|
}
|
|
268
|
+
})
|
|
269
|
+
};
|
|
270
|
+
if ("viewOf" in astNode) {
|
|
271
|
+
const viewOfEl = elementRef(astNode.viewOf);
|
|
272
|
+
const viewOf = viewOfEl && this.resolveFqn(viewOfEl);
|
|
273
|
+
invariant(viewOf, " viewOf is not resolved: " + astNode.$cstNode?.text);
|
|
274
|
+
return {
|
|
275
|
+
...basic,
|
|
276
|
+
viewOf
|
|
277
|
+
};
|
|
278
|
+
}
|
|
279
|
+
if ("extends" in astNode) {
|
|
280
|
+
const extendsView = astNode.extends.view.ref;
|
|
281
|
+
invariant(extendsView?.name, "view extends is not resolved: " + astNode.$cstNode?.text);
|
|
282
|
+
return {
|
|
283
|
+
...basic,
|
|
284
|
+
extends: extendsView.name
|
|
285
|
+
};
|
|
286
|
+
}
|
|
287
|
+
return basic;
|
|
288
|
+
}
|
|
289
|
+
resolveFqn(node) {
|
|
290
|
+
if (ast.isExtendElement(node)) {
|
|
291
|
+
return fqnElementRef(node.element);
|
|
292
|
+
}
|
|
293
|
+
const fqn = this.fqnIndex.getFqn(node);
|
|
294
|
+
invariant(fqn, `Not indexed element: ${this.getAstNodePath(node)}`);
|
|
295
|
+
return fqn;
|
|
296
|
+
}
|
|
297
|
+
getAstNodePath(node) {
|
|
298
|
+
return this.services.workspace.AstNodeLocator.getAstNodePath(node);
|
|
299
|
+
}
|
|
300
|
+
convertTags(withTags) {
|
|
301
|
+
if (!withTags) {
|
|
302
|
+
return null;
|
|
307
303
|
}
|
|
304
|
+
const tags = withTags.tags?.value.flatMap(({ ref }) => ref ? ref.name : []);
|
|
305
|
+
return tags && isNonEmptyArray(tags) ? tags : null;
|
|
306
|
+
}
|
|
308
307
|
}
|
|
309
|
-
//# sourceMappingURL=model-parser.js.map
|
package/dist/module.d.ts
CHANGED
|
@@ -1,10 +1,13 @@
|
|
|
1
|
-
import type
|
|
1
|
+
import { WorkspaceCache, type DefaultSharedModuleContext, type LangiumServices, type LangiumSharedServices, type Module, type PartialLangiumServices } from 'langium';
|
|
2
2
|
import { LikeC4DocumentSymbolProvider } from './lsp';
|
|
3
3
|
import { FqnIndex, LikeC4ModelBuilder, LikeC4ModelLocator, LikeC4ModelParser } from './model';
|
|
4
|
+
import { Rpc } from './Rpc';
|
|
4
5
|
/**
|
|
5
6
|
* Declaration of custom services - add your own service classes here.
|
|
6
7
|
*/
|
|
7
8
|
export interface LikeC4AddedServices {
|
|
9
|
+
WorkspaceCache: WorkspaceCache<string, any>;
|
|
10
|
+
Rpc: Rpc;
|
|
8
11
|
likec4: {
|
|
9
12
|
FqnIndex: FqnIndex;
|
|
10
13
|
ModelParser: LikeC4ModelParser;
|