@likec4/language-server 0.33.1 → 0.34.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 +17 -3
- package/dist/ast.d.ts +24 -11
- package/dist/ast.js +11 -8
- package/dist/elementRef.d.ts +1 -1
- package/dist/elementRef.js +2 -3
- package/dist/generated/ast.d.ts +29 -10
- package/dist/generated/ast.js +20 -1
- package/dist/generated/grammar.d.ts +1 -1
- package/dist/generated/grammar.js +11 -11
- package/dist/generated/module.d.ts +7 -3
- package/dist/generated/module.js +3 -3
- package/dist/index.d.ts +1 -0
- package/dist/index.js +1 -0
- package/dist/logger.d.ts +6 -4
- package/dist/logger.js +34 -6
- package/dist/{shared → lsp}/CodeLensProvider.d.ts +3 -3
- package/dist/{shared → lsp}/DocumentLinkProvider.d.ts +3 -2
- package/dist/{shared → lsp}/DocumentLinkProvider.js +3 -3
- package/dist/lsp/DocumentSymbolProvider.js +3 -3
- package/dist/lsp/index.d.ts +2 -0
- package/dist/lsp/index.js +2 -0
- package/dist/model/fqn-computation.js +6 -3
- package/dist/model/fqn-index.d.ts +4 -7
- package/dist/model/fqn-index.js +36 -21
- package/dist/model/index.d.ts +1 -0
- package/dist/model/index.js +1 -0
- package/dist/model/model-builder.d.ts +1 -18
- package/dist/model/model-builder.js +111 -340
- package/dist/model/model-locator.js +5 -9
- package/dist/model/model-parser.d.ts +27 -0
- package/dist/model/model-parser.js +281 -0
- package/dist/module.d.ts +2 -1
- package/dist/module.js +20 -29
- package/dist/protocol.d.ts +8 -16
- package/dist/protocol.js +2 -6
- package/dist/references/scope-provider.js +2 -3
- package/dist/registerProtocolHandlers.js +19 -16
- package/dist/shared/index.d.ts +0 -2
- package/dist/shared/index.js +0 -2
- package/dist/test/testServices.d.ts +2 -2
- package/dist/test/testServices.js +16 -10
- package/dist/utils.d.ts +2 -2
- package/dist/utils.js +2 -7
- package/dist/validation/element.d.ts +1 -1
- package/dist/validation/element.js +16 -3
- package/dist/validation/index.js +26 -0
- package/dist/validation/relation.js +3 -10
- package/package.json +6 -5
- /package/dist/{shared → lsp}/CodeLensProvider.js +0 -0
|
@@ -0,0 +1,281 @@
|
|
|
1
|
+
import { InvalidModelError, invariant, isNonEmptyArray, nonexhaustive } from '@likec4/core';
|
|
2
|
+
import { DocumentState, getDocument, interruptAndCheck } from 'langium';
|
|
3
|
+
import objectHash from 'object-hash';
|
|
4
|
+
import stripIndent from 'strip-indent';
|
|
5
|
+
import { Disposable } from 'vscode-languageserver-protocol';
|
|
6
|
+
import { ElementViewOps, ast, cleanParsedModel, isLikeC4LangiumDocument, resolveRelationPoints, streamModel, toAutoLayout, toElementStyle, toElementStyleExcludeDefaults } from '../ast';
|
|
7
|
+
import { elementRef, strictElementRefFqn } from '../elementRef';
|
|
8
|
+
import { logError, logWarnError, logger } from '../logger';
|
|
9
|
+
import { printDocs } from '../utils';
|
|
10
|
+
export class LikeC4ModelParser {
|
|
11
|
+
services;
|
|
12
|
+
fqnIndex;
|
|
13
|
+
listeners = [];
|
|
14
|
+
constructor(services) {
|
|
15
|
+
this.services = services;
|
|
16
|
+
this.fqnIndex = services.likec4.FqnIndex;
|
|
17
|
+
services.shared.workspace.DocumentBuilder.onBuildPhase(DocumentState.Validated, async (docs, cancelToken) => await this.onValidated(docs, cancelToken));
|
|
18
|
+
}
|
|
19
|
+
onParsed(callback) {
|
|
20
|
+
this.listeners.push(callback);
|
|
21
|
+
return Disposable.create(() => {
|
|
22
|
+
const index = this.listeners.indexOf(callback);
|
|
23
|
+
if (index >= 0) {
|
|
24
|
+
this.listeners.splice(index, 1);
|
|
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
|
+
}
|
|
42
|
+
}
|
|
43
|
+
if (countOfChangedDocs > 0) {
|
|
44
|
+
this.notifyListeners();
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
async parseDocument(doc, cancelToken) {
|
|
48
|
+
const { elements, relations, views, specification } = cleanParsedModel(doc);
|
|
49
|
+
const specs = doc.parseResult.value.specification?.specs.filter(ast.isSpecificationElementKind);
|
|
50
|
+
if (specs) {
|
|
51
|
+
for (const { kind, style } of specs) {
|
|
52
|
+
try {
|
|
53
|
+
specification.kinds[kind.name] = toElementStyleExcludeDefaults(style?.props);
|
|
54
|
+
}
|
|
55
|
+
catch (e) {
|
|
56
|
+
logWarnError(e);
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
await interruptAndCheck(cancelToken);
|
|
61
|
+
for (const el of streamModel(doc)) {
|
|
62
|
+
if (ast.isElement(el)) {
|
|
63
|
+
try {
|
|
64
|
+
elements.push(this.parseElement(el));
|
|
65
|
+
}
|
|
66
|
+
catch (e) {
|
|
67
|
+
logWarnError(e);
|
|
68
|
+
}
|
|
69
|
+
continue;
|
|
70
|
+
}
|
|
71
|
+
if (ast.isRelation(el)) {
|
|
72
|
+
try {
|
|
73
|
+
relations.push(this.parseRelation(el));
|
|
74
|
+
}
|
|
75
|
+
catch (e) {
|
|
76
|
+
logWarnError(e);
|
|
77
|
+
}
|
|
78
|
+
continue;
|
|
79
|
+
}
|
|
80
|
+
nonexhaustive(el);
|
|
81
|
+
}
|
|
82
|
+
await interruptAndCheck(cancelToken);
|
|
83
|
+
const docviews = doc.parseResult.value.views?.views;
|
|
84
|
+
if (docviews) {
|
|
85
|
+
for (const view of docviews) {
|
|
86
|
+
try {
|
|
87
|
+
const v = this.parseElementView(view);
|
|
88
|
+
ElementViewOps.writeId(view, v.id);
|
|
89
|
+
views.push(v);
|
|
90
|
+
}
|
|
91
|
+
catch (e) {
|
|
92
|
+
logWarnError(e);
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
// const prevHash = doc.c4hash ?? ''
|
|
97
|
+
// doc.c4hash = c4hash(doc)
|
|
98
|
+
// return prevHash !== doc.c4hash
|
|
99
|
+
}
|
|
100
|
+
parseElement(astNode) {
|
|
101
|
+
const id = this.resolveFqn(astNode);
|
|
102
|
+
invariant(astNode.kind.ref, 'Element kind is not resolved: ' + astNode.name);
|
|
103
|
+
const kind = astNode.kind.ref.name;
|
|
104
|
+
const tags = this.convertTags(astNode.body);
|
|
105
|
+
const stylePropsAst = astNode.body?.props.find(ast.isStyleProperties)?.props;
|
|
106
|
+
const styleProps = toElementStyleExcludeDefaults(stylePropsAst);
|
|
107
|
+
const astPath = this.getAstNodePath(astNode);
|
|
108
|
+
let [title, description, technology] = astNode.props;
|
|
109
|
+
const bodyProps = astNode.body?.props.filter((p) => ast.isElementStringProperty(p)) ?? [];
|
|
110
|
+
title = title ?? bodyProps.find(p => p.key === 'title')?.value;
|
|
111
|
+
description = description ?? bodyProps.find(p => p.key === 'description')?.value;
|
|
112
|
+
technology = technology ?? bodyProps.find(p => p.key === 'technology')?.value;
|
|
113
|
+
const links = astNode.body?.props.filter(ast.isLinkProperty).map(p => p.value);
|
|
114
|
+
return {
|
|
115
|
+
id,
|
|
116
|
+
kind,
|
|
117
|
+
astPath,
|
|
118
|
+
title: title ? stripIndent(title).trim() : astNode.name,
|
|
119
|
+
...(tags && { tags }),
|
|
120
|
+
...(links && isNonEmptyArray(links) && { links }),
|
|
121
|
+
...(technology && { technology }),
|
|
122
|
+
...(description && { description: stripIndent(description).trim() }),
|
|
123
|
+
...styleProps
|
|
124
|
+
};
|
|
125
|
+
}
|
|
126
|
+
parseRelation(astNode) {
|
|
127
|
+
const coupling = resolveRelationPoints(astNode);
|
|
128
|
+
const target = this.resolveFqn(coupling.target);
|
|
129
|
+
const source = this.resolveFqn(coupling.source);
|
|
130
|
+
const hashdata = {
|
|
131
|
+
astPath: this.getAstNodePath(astNode),
|
|
132
|
+
source,
|
|
133
|
+
target
|
|
134
|
+
};
|
|
135
|
+
const id = objectHash(hashdata);
|
|
136
|
+
const title = astNode.title ?? astNode.body?.props.find(p => p.key === 'title')?.value ?? '';
|
|
137
|
+
return {
|
|
138
|
+
id,
|
|
139
|
+
...hashdata,
|
|
140
|
+
title
|
|
141
|
+
};
|
|
142
|
+
}
|
|
143
|
+
parseElementExpression(astNode) {
|
|
144
|
+
if (ast.isWildcardExpression(astNode)) {
|
|
145
|
+
return {
|
|
146
|
+
wildcard: true
|
|
147
|
+
};
|
|
148
|
+
}
|
|
149
|
+
if (ast.isElementKindExpression(astNode)) {
|
|
150
|
+
invariant(astNode.kind.ref, 'ElementKindExpression kind is not resolved: ' + astNode.$cstNode?.text);
|
|
151
|
+
return {
|
|
152
|
+
elementKind: astNode.kind.ref.name,
|
|
153
|
+
isEqual: astNode.isEqual
|
|
154
|
+
};
|
|
155
|
+
}
|
|
156
|
+
if (ast.isElementTagExpression(astNode)) {
|
|
157
|
+
invariant(astNode.tag.ref, 'ElementTagExpression tag is not resolved: ' + astNode.$cstNode?.text);
|
|
158
|
+
return {
|
|
159
|
+
elementTag: astNode.tag.ref.name,
|
|
160
|
+
isEqual: astNode.isEqual
|
|
161
|
+
};
|
|
162
|
+
}
|
|
163
|
+
if (ast.isElementRefExpression(astNode)) {
|
|
164
|
+
const element = elementRef(astNode.id);
|
|
165
|
+
invariant(element, 'Element not found ' + astNode.id.$cstNode?.text);
|
|
166
|
+
return {
|
|
167
|
+
element: this.resolveFqn(element),
|
|
168
|
+
isDescedants: astNode.isDescedants
|
|
169
|
+
};
|
|
170
|
+
}
|
|
171
|
+
nonexhaustive(astNode);
|
|
172
|
+
}
|
|
173
|
+
parseExpression(astNode) {
|
|
174
|
+
if (ast.isElementExpression(astNode)) {
|
|
175
|
+
return this.parseElementExpression(astNode);
|
|
176
|
+
}
|
|
177
|
+
if (ast.isIncomingExpression(astNode)) {
|
|
178
|
+
return {
|
|
179
|
+
incoming: this.parseElementExpression(astNode.target)
|
|
180
|
+
};
|
|
181
|
+
}
|
|
182
|
+
if (ast.isOutgoingExpression(astNode)) {
|
|
183
|
+
return {
|
|
184
|
+
outgoing: this.parseElementExpression(astNode.source)
|
|
185
|
+
};
|
|
186
|
+
}
|
|
187
|
+
if (ast.isInOutExpression(astNode)) {
|
|
188
|
+
return {
|
|
189
|
+
inout: this.parseElementExpression(astNode.inout.target)
|
|
190
|
+
};
|
|
191
|
+
}
|
|
192
|
+
if (ast.isRelationExpression(astNode)) {
|
|
193
|
+
return {
|
|
194
|
+
source: this.parseElementExpression(astNode.source),
|
|
195
|
+
target: this.parseElementExpression(astNode.target)
|
|
196
|
+
};
|
|
197
|
+
}
|
|
198
|
+
nonexhaustive(astNode);
|
|
199
|
+
}
|
|
200
|
+
parseViewRule(astRule) {
|
|
201
|
+
if (ast.isViewRuleExpression(astRule)) {
|
|
202
|
+
const exprs = astRule.expressions.map(n => this.parseExpression(n));
|
|
203
|
+
return {
|
|
204
|
+
isInclude: astRule.isInclude,
|
|
205
|
+
exprs
|
|
206
|
+
};
|
|
207
|
+
}
|
|
208
|
+
if (ast.isViewRuleStyle(astRule)) {
|
|
209
|
+
const styleProps = toElementStyle(astRule.props);
|
|
210
|
+
return {
|
|
211
|
+
targets: astRule.targets.map(n => this.parseElementExpression(n)),
|
|
212
|
+
style: {
|
|
213
|
+
...styleProps
|
|
214
|
+
}
|
|
215
|
+
};
|
|
216
|
+
}
|
|
217
|
+
if (ast.isViewRuleAutoLayout(astRule)) {
|
|
218
|
+
return {
|
|
219
|
+
autoLayout: toAutoLayout(astRule.direction)
|
|
220
|
+
};
|
|
221
|
+
}
|
|
222
|
+
nonexhaustive(astRule);
|
|
223
|
+
}
|
|
224
|
+
parseElementView(astNode) {
|
|
225
|
+
const viewOfEl = astNode.viewOf && elementRef(astNode.viewOf);
|
|
226
|
+
const viewOf = viewOfEl && this.resolveFqn(viewOfEl);
|
|
227
|
+
const astPath = this.getAstNodePath(astNode);
|
|
228
|
+
let id = astNode.name;
|
|
229
|
+
if (!id) {
|
|
230
|
+
const doc = getDocument(astNode).uri.toString();
|
|
231
|
+
id = objectHash({
|
|
232
|
+
doc,
|
|
233
|
+
astPath,
|
|
234
|
+
viewOf: viewOf ?? null
|
|
235
|
+
});
|
|
236
|
+
}
|
|
237
|
+
const title = astNode.props.find(p => p.key === 'title')?.value;
|
|
238
|
+
const description = astNode.props.find(p => p.key === 'description')?.value;
|
|
239
|
+
const tags = this.convertTags(astNode);
|
|
240
|
+
const links = astNode.props.filter(ast.isLinkProperty).map(p => p.value);
|
|
241
|
+
return {
|
|
242
|
+
id,
|
|
243
|
+
astPath,
|
|
244
|
+
...(viewOf && { viewOf }),
|
|
245
|
+
...(title && { title }),
|
|
246
|
+
...(description && { description }),
|
|
247
|
+
...(tags && { tags }),
|
|
248
|
+
...(links && isNonEmptyArray(links) && { links }),
|
|
249
|
+
rules: astNode.rules.map(n => this.parseViewRule(n))
|
|
250
|
+
};
|
|
251
|
+
}
|
|
252
|
+
resolveFqn(node) {
|
|
253
|
+
if (ast.isExtendElement(node)) {
|
|
254
|
+
return strictElementRefFqn(node.element);
|
|
255
|
+
}
|
|
256
|
+
const fqn = this.fqnIndex.getFqn(node);
|
|
257
|
+
invariant(fqn, `Not indexed element: ${this.getAstNodePath(node)}`);
|
|
258
|
+
return fqn;
|
|
259
|
+
}
|
|
260
|
+
getAstNodePath(node) {
|
|
261
|
+
return this.services.workspace.AstNodeLocator.getAstNodePath(node);
|
|
262
|
+
}
|
|
263
|
+
convertTags(withTags) {
|
|
264
|
+
if (!withTags) {
|
|
265
|
+
return null;
|
|
266
|
+
}
|
|
267
|
+
const tags = withTags.tags?.value.flatMap(({ ref }) => (ref ? ref.name : []));
|
|
268
|
+
return tags && isNonEmptyArray(tags) ? tags : null;
|
|
269
|
+
}
|
|
270
|
+
notifyListeners() {
|
|
271
|
+
for (const listener of this.listeners) {
|
|
272
|
+
try {
|
|
273
|
+
listener();
|
|
274
|
+
}
|
|
275
|
+
catch (e) {
|
|
276
|
+
logError(e);
|
|
277
|
+
}
|
|
278
|
+
}
|
|
279
|
+
}
|
|
280
|
+
}
|
|
281
|
+
//# sourceMappingURL=model-parser.js.map
|
package/dist/module.d.ts
CHANGED
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
import type { DefaultSharedModuleContext, LangiumServices, LangiumSharedServices, Module, PartialLangiumServices } from 'langium';
|
|
2
2
|
import { LikeC4DocumentSymbolProvider } from './lsp';
|
|
3
|
-
import { FqnIndex, LikeC4ModelBuilder, LikeC4ModelLocator } from './model';
|
|
3
|
+
import { FqnIndex, LikeC4ModelBuilder, LikeC4ModelLocator, LikeC4ModelParser } from './model';
|
|
4
4
|
/**
|
|
5
5
|
* Declaration of custom services - add your own service classes here.
|
|
6
6
|
*/
|
|
7
7
|
export interface LikeC4AddedServices {
|
|
8
8
|
likec4: {
|
|
9
9
|
FqnIndex: FqnIndex;
|
|
10
|
+
ModelParser: LikeC4ModelParser;
|
|
10
11
|
ModelBuilder: LikeC4ModelBuilder;
|
|
11
12
|
ModelLocator: LikeC4ModelLocator;
|
|
12
13
|
};
|
package/dist/module.js
CHANGED
|
@@ -1,25 +1,29 @@
|
|
|
1
1
|
import { EmptyFileSystem, createDefaultModule, createDefaultSharedModule, inject } from 'langium';
|
|
2
2
|
import { LikeC4GeneratedModule, LikeC4GeneratedSharedModule } from './generated/module';
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
import { FqnIndex, LikeC4ModelBuilder, LikeC4ModelLocator } from './model';
|
|
3
|
+
import { LikeC4CodeLensProvider, LikeC4DocumentLinkProvider, LikeC4DocumentSymbolProvider, LikeC4HoverProvider, LikeC4SemanticTokenProvider } from './lsp';
|
|
4
|
+
import { FqnIndex, LikeC4ModelBuilder, LikeC4ModelLocator, LikeC4ModelParser } from './model';
|
|
6
5
|
import { LikeC4ScopeComputation, LikeC4ScopeProvider } from './references';
|
|
7
6
|
import { registerProtocolHandlers } from './registerProtocolHandlers';
|
|
8
|
-
import {
|
|
7
|
+
import { LikeC4WorkspaceManager } from './shared';
|
|
9
8
|
import { registerValidationChecks } from './validation';
|
|
9
|
+
import { logger } from './logger';
|
|
10
|
+
import { serializeError } from '@likec4/core';
|
|
10
11
|
function bind(Type) {
|
|
11
12
|
return (services) => new Type(services);
|
|
12
13
|
}
|
|
13
14
|
export const LikeC4Module = {
|
|
14
15
|
likec4: {
|
|
15
16
|
FqnIndex: bind(FqnIndex),
|
|
17
|
+
ModelParser: bind(LikeC4ModelParser),
|
|
16
18
|
ModelBuilder: bind(LikeC4ModelBuilder),
|
|
17
19
|
ModelLocator: bind(LikeC4ModelLocator)
|
|
18
20
|
},
|
|
19
21
|
lsp: {
|
|
20
22
|
DocumentSymbolProvider: bind(LikeC4DocumentSymbolProvider),
|
|
21
23
|
SemanticTokenProvider: bind(LikeC4SemanticTokenProvider),
|
|
22
|
-
HoverProvider: bind(LikeC4HoverProvider)
|
|
24
|
+
HoverProvider: bind(LikeC4HoverProvider),
|
|
25
|
+
CodeLensProvider: bind(LikeC4CodeLensProvider),
|
|
26
|
+
DocumentLinkProvider: bind(LikeC4DocumentLinkProvider)
|
|
23
27
|
},
|
|
24
28
|
//
|
|
25
29
|
// // Formatter: bind(LikeC4Formatter),
|
|
@@ -31,44 +35,31 @@ export const LikeC4Module = {
|
|
|
31
35
|
}
|
|
32
36
|
};
|
|
33
37
|
const LikeC4SharedModule = {
|
|
34
|
-
...LikeC4GeneratedSharedModule,
|
|
35
38
|
workspace: {
|
|
36
39
|
WorkspaceManager: services => new LikeC4WorkspaceManager(services)
|
|
37
|
-
},
|
|
38
|
-
lsp: {
|
|
39
|
-
CodeLensProvider: services => new LikeC4CodeLensProvider(services),
|
|
40
|
-
DocumentLinkProvider: services => new LikeC4DocumentLinkProvider(services)
|
|
41
40
|
}
|
|
42
41
|
};
|
|
43
42
|
export function createLanguageServices(context) {
|
|
44
43
|
const connection = context?.connection;
|
|
45
44
|
if (connection) {
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
}
|
|
54
|
-
catch (error) {
|
|
55
|
-
console.error(error);
|
|
45
|
+
// eslint-disable-next-line @typescript-eslint/unbound-method
|
|
46
|
+
const original = logger.error.bind(logger);
|
|
47
|
+
logger.error = (arg) => {
|
|
48
|
+
if (typeof arg === 'string') {
|
|
49
|
+
original(arg);
|
|
50
|
+
connection.telemetry.logEvent({ eventName: 'error', error: arg });
|
|
51
|
+
return;
|
|
56
52
|
}
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
logger.warn = log('warn');
|
|
61
|
-
logger.error = log('error');
|
|
62
|
-
logger.trace = logger.debug = (message) => {
|
|
63
|
-
console.debug(message);
|
|
64
|
-
connection.tracer.log(message);
|
|
53
|
+
const { message, error } = serializeError(arg);
|
|
54
|
+
original(error);
|
|
55
|
+
connection.telemetry.logEvent({ eventName: 'error', error: message });
|
|
65
56
|
};
|
|
66
57
|
}
|
|
67
58
|
const moduleContext = {
|
|
68
59
|
...EmptyFileSystem,
|
|
69
60
|
...context
|
|
70
61
|
};
|
|
71
|
-
const shared = inject(createDefaultSharedModule(moduleContext), LikeC4SharedModule);
|
|
62
|
+
const shared = inject(createDefaultSharedModule(moduleContext), LikeC4GeneratedSharedModule, LikeC4SharedModule);
|
|
72
63
|
const likec4 = inject(createDefaultModule({ shared }), LikeC4GeneratedModule, LikeC4Module);
|
|
73
64
|
shared.ServiceRegistry.register(likec4);
|
|
74
65
|
registerValidationChecks(likec4);
|
package/dist/protocol.d.ts
CHANGED
|
@@ -4,17 +4,15 @@ import { NotificationType, RequestType0, RequestType } from 'vscode-languageserv
|
|
|
4
4
|
interface BuildDocumentsParams {
|
|
5
5
|
docs: DocumentUri[];
|
|
6
6
|
}
|
|
7
|
-
export
|
|
7
|
+
export type LocateParams = {
|
|
8
8
|
element: Fqn;
|
|
9
9
|
property?: string;
|
|
10
|
-
}
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
}
|
|
15
|
-
export declare const
|
|
16
|
-
id: ViewID;
|
|
17
|
-
}, Location | null, void>;
|
|
10
|
+
} | {
|
|
11
|
+
relation: RelationID;
|
|
12
|
+
} | {
|
|
13
|
+
view: ViewID;
|
|
14
|
+
};
|
|
15
|
+
export declare const locate: RequestType<LocateParams, Location | null, void>;
|
|
18
16
|
export declare const Rpc: {
|
|
19
17
|
readonly onDidChangeModel: NotificationType<string>;
|
|
20
18
|
readonly fetchModel: RequestType0<{
|
|
@@ -24,13 +22,7 @@ export declare const Rpc: {
|
|
|
24
22
|
docs: DocumentUri[];
|
|
25
23
|
}, void>;
|
|
26
24
|
readonly buildDocuments: RequestType<BuildDocumentsParams, void, void>;
|
|
27
|
-
readonly
|
|
28
|
-
readonly locateRelation: RequestType<{
|
|
29
|
-
id: RelationID;
|
|
30
|
-
}, Location | null, void>;
|
|
31
|
-
readonly locateView: RequestType<{
|
|
32
|
-
id: ViewID;
|
|
33
|
-
}, Location | null, void>;
|
|
25
|
+
readonly locate: RequestType<LocateParams, Location | null, void>;
|
|
34
26
|
};
|
|
35
27
|
export {};
|
|
36
28
|
//# sourceMappingURL=protocol.d.ts.map
|
package/dist/protocol.js
CHANGED
|
@@ -6,17 +6,13 @@ const onDidChangeModel = new NotificationType('likec4/onDidChangeModel');
|
|
|
6
6
|
const fetchModel = new RequestType0('likec4/fetchModel');
|
|
7
7
|
const rebuild = new RequestType0('likec4/rebuildModel');
|
|
8
8
|
const buildDocuments = new RequestType('likec4/buildDocuments');
|
|
9
|
-
export const
|
|
10
|
-
export const locateRelation = new RequestType('likec4/locateRelation');
|
|
11
|
-
export const locateView = new RequestType('likec4/locateView');
|
|
9
|
+
export const locate = new RequestType('likec4/locate');
|
|
12
10
|
//#endregion
|
|
13
11
|
export const Rpc = {
|
|
14
12
|
onDidChangeModel,
|
|
15
13
|
fetchModel,
|
|
16
14
|
rebuild,
|
|
17
15
|
buildDocuments,
|
|
18
|
-
|
|
19
|
-
locateRelation,
|
|
20
|
-
locateView
|
|
16
|
+
locate
|
|
21
17
|
};
|
|
22
18
|
//# sourceMappingURL=protocol.js.map
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { DONE_RESULT, DefaultScopeProvider, EMPTY_STREAM, StreamImpl, StreamScope, getDocument, stream } from 'langium';
|
|
2
2
|
import { ast } from '../ast';
|
|
3
3
|
import { elementRef, isElementRefHead, parentStrictElementRef } from '../elementRef';
|
|
4
|
-
import {
|
|
4
|
+
import { logError } from '../logger';
|
|
5
5
|
function toAstNodeDescription(entry) {
|
|
6
6
|
return {
|
|
7
7
|
documentUri: entry.doc.uri,
|
|
@@ -71,8 +71,7 @@ export class LikeC4ScopeProvider extends DefaultScopeProvider {
|
|
|
71
71
|
return this.computeScope(container, referenceType);
|
|
72
72
|
}
|
|
73
73
|
catch (e) {
|
|
74
|
-
|
|
75
|
-
logger.error(e);
|
|
74
|
+
logError(e);
|
|
76
75
|
return this.getGlobalScope(referenceType);
|
|
77
76
|
}
|
|
78
77
|
}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { URI } from 'vscode-uri';
|
|
2
|
-
import { logger } from './logger';
|
|
2
|
+
import { logger, logError } from './logger';
|
|
3
3
|
import { Rpc } from './protocol';
|
|
4
|
+
import { nonexhaustive } from '@likec4/core';
|
|
4
5
|
export function registerProtocolHandlers(services) {
|
|
5
6
|
const connection = services.shared.lsp.Connection;
|
|
6
7
|
if (!connection) {
|
|
@@ -16,13 +17,13 @@ export function registerProtocolHandlers(services) {
|
|
|
16
17
|
}
|
|
17
18
|
catch (e) {
|
|
18
19
|
model = null;
|
|
19
|
-
|
|
20
|
+
logError(e);
|
|
20
21
|
}
|
|
21
22
|
return Promise.resolve({ model });
|
|
22
23
|
});
|
|
23
24
|
connection.onRequest(Rpc.rebuild, async (cancelToken) => {
|
|
24
25
|
const changed = LangiumDocuments.all.map(d => d.uri).toArray();
|
|
25
|
-
logger.debug(`
|
|
26
|
+
logger.debug(`[ProtocolHandlers] rebuild all documents: [
|
|
26
27
|
${changed.map(d => d.toString()).join('\n ')}
|
|
27
28
|
]`);
|
|
28
29
|
await services.shared.workspace.DocumentBuilder.update(changed, [], cancelToken);
|
|
@@ -32,12 +33,11 @@ export function registerProtocolHandlers(services) {
|
|
|
32
33
|
});
|
|
33
34
|
connection.onRequest(Rpc.buildDocuments, async ({ docs }, cancelToken) => {
|
|
34
35
|
if (docs.length === 0) {
|
|
35
|
-
logger.debug(`
|
|
36
|
+
logger.debug(`[ProtocolHandlers] received empty request to rebuild`);
|
|
36
37
|
return;
|
|
37
38
|
}
|
|
38
|
-
logger.debug(`
|
|
39
|
-
|
|
40
|
-
]`);
|
|
39
|
+
logger.debug(`[ProtocolHandlers] received request to buildDocuments:
|
|
40
|
+
- ${docs.join('\n - ')}`);
|
|
41
41
|
const changed = [];
|
|
42
42
|
for (const d of docs) {
|
|
43
43
|
try {
|
|
@@ -51,7 +51,7 @@ export function registerProtocolHandlers(services) {
|
|
|
51
51
|
}
|
|
52
52
|
}
|
|
53
53
|
catch (e) {
|
|
54
|
-
|
|
54
|
+
logError(e);
|
|
55
55
|
}
|
|
56
56
|
}
|
|
57
57
|
if (changed.length !== docs.length) {
|
|
@@ -67,14 +67,17 @@ We rebuild: [
|
|
|
67
67
|
}
|
|
68
68
|
await services.shared.workspace.DocumentBuilder.update(changed, [], cancelToken);
|
|
69
69
|
});
|
|
70
|
-
connection.onRequest(Rpc.
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
70
|
+
connection.onRequest(Rpc.locate, params => {
|
|
71
|
+
if ('element' in params) {
|
|
72
|
+
return modelLocator.locateElement(params.element, params.property ?? 'name');
|
|
73
|
+
}
|
|
74
|
+
if ('relation' in params) {
|
|
75
|
+
return modelLocator.locateRelation(params.relation);
|
|
76
|
+
}
|
|
77
|
+
if ('view' in params) {
|
|
78
|
+
return modelLocator.locateView(params.view);
|
|
79
|
+
}
|
|
80
|
+
nonexhaustive(params);
|
|
78
81
|
});
|
|
79
82
|
}
|
|
80
83
|
//# sourceMappingURL=registerProtocolHandlers.js.map
|
package/dist/shared/index.d.ts
CHANGED
package/dist/shared/index.js
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import type { LikeC4LangiumDocument } from '../ast';
|
|
2
|
-
export declare function createTestServices(): {
|
|
2
|
+
export declare function createTestServices(workspace?: string): {
|
|
3
3
|
services: import("../module").LikeC4Services;
|
|
4
4
|
parse: (input: string, uri?: string) => Promise<LikeC4LangiumDocument>;
|
|
5
|
-
validate: (input: string | LikeC4LangiumDocument) => Promise<{
|
|
5
|
+
validate: (input: string | LikeC4LangiumDocument, uri?: string) => Promise<{
|
|
6
6
|
document: LikeC4LangiumDocument;
|
|
7
7
|
diagnostics: import("vscode-languageserver-types").Diagnostic[];
|
|
8
8
|
errors: string[];
|
|
@@ -1,27 +1,33 @@
|
|
|
1
1
|
import { createLanguageServices } from '../module';
|
|
2
2
|
import { EmptyFileSystem } from 'langium';
|
|
3
|
-
import { URI } from 'vscode-uri';
|
|
3
|
+
import { URI, Utils } from 'vscode-uri';
|
|
4
4
|
import stripIndent from 'strip-indent';
|
|
5
|
-
export function createTestServices() {
|
|
5
|
+
export function createTestServices(workspace = 'file:///test/workspace') {
|
|
6
6
|
const services = createLanguageServices(EmptyFileSystem).likec4;
|
|
7
7
|
const metaData = services.LanguageMetaData;
|
|
8
8
|
const langiumDocuments = services.shared.workspace.LangiumDocuments;
|
|
9
9
|
const documentBuilder = services.shared.workspace.DocumentBuilder;
|
|
10
10
|
const modelBuilder = services.likec4.ModelBuilder;
|
|
11
|
-
const
|
|
11
|
+
const workspaceUri = URI.parse(workspace);
|
|
12
|
+
const initPromise = services.shared.workspace.WorkspaceManager.initializeWorkspace([
|
|
13
|
+
{
|
|
14
|
+
name: 'test',
|
|
15
|
+
uri: workspaceUri.toString()
|
|
16
|
+
}
|
|
17
|
+
]);
|
|
12
18
|
let documentIndex = 1;
|
|
13
19
|
const parse = async (input, uri) => {
|
|
14
20
|
await initPromise;
|
|
15
|
-
|
|
16
|
-
const document = services.shared.workspace.LangiumDocumentFactory.fromString(stripIndent(input),
|
|
21
|
+
const docUri = Utils.joinPath(workspaceUri, '/src/', uri ?? `${documentIndex++}${metaData.fileExtensions[0]}`);
|
|
22
|
+
const document = services.shared.workspace.LangiumDocumentFactory.fromString(stripIndent(input), docUri);
|
|
17
23
|
langiumDocuments.addDocument(document);
|
|
18
|
-
await documentBuilder.build([document], {
|
|
24
|
+
await documentBuilder.build([document], { validation: false });
|
|
19
25
|
return document;
|
|
20
26
|
};
|
|
21
|
-
const validate = async (input) => {
|
|
27
|
+
const validate = async (input, uri) => {
|
|
22
28
|
await initPromise;
|
|
23
|
-
const document = typeof input === 'string' ? await parse(input) : input;
|
|
24
|
-
await documentBuilder.build([document], {
|
|
29
|
+
const document = typeof input === 'string' ? await parse(input, uri) : input;
|
|
30
|
+
await documentBuilder.build([document], { validation: true });
|
|
25
31
|
const diagnostics = document.diagnostics ?? [];
|
|
26
32
|
const errors = diagnostics.map(d => d.message);
|
|
27
33
|
return {
|
|
@@ -33,7 +39,7 @@ export function createTestServices() {
|
|
|
33
39
|
const validateAll = async () => {
|
|
34
40
|
await initPromise;
|
|
35
41
|
const docs = langiumDocuments.all.toArray();
|
|
36
|
-
await documentBuilder.build(docs, {
|
|
42
|
+
await documentBuilder.build(docs, { validation: true });
|
|
37
43
|
const diagnostics = docs.flatMap(doc => doc.diagnostics ?? []);
|
|
38
44
|
const errors = diagnostics.map(d => d.message);
|
|
39
45
|
return {
|
package/dist/utils.d.ts
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
|
|
2
|
-
export declare
|
|
1
|
+
import type { LangiumDocument } from 'langium';
|
|
2
|
+
export declare const printDocs: (docs: LangiumDocument[]) => string;
|
|
3
3
|
//# sourceMappingURL=utils.d.ts.map
|
package/dist/utils.js
CHANGED
|
@@ -1,8 +1,3 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
}
|
|
4
|
-
export function ignoreNeverInRuntime(arg) {
|
|
5
|
-
console.warn(`Unexpected and ignored value: ${JSON.stringify(arg)}`);
|
|
6
|
-
// throw new Error(`Unexpected value: ${arg}`);
|
|
7
|
-
}
|
|
1
|
+
import { Utils } from 'vscode-uri';
|
|
2
|
+
export const printDocs = (docs) => docs.map(d => ' - ' + Utils.basename(d.uri)).join('\n');
|
|
8
3
|
//# sourceMappingURL=utils.js.map
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type
|
|
1
|
+
import { type ValidationCheck } from 'langium';
|
|
2
2
|
import type { ast } from '../ast';
|
|
3
3
|
import type { LikeC4Services } from '../module';
|
|
4
4
|
export declare const elementChecks: (services: LikeC4Services) => ValidationCheck<ast.Element>;
|