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