@likec4/language-server 0.4.0 → 0.6.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/ast.d.ts +1 -0
- package/dist/ast.js +26 -24
- package/dist/builtin.d.ts +4 -0
- package/dist/builtin.js +8 -0
- package/dist/generated/ast.d.ts +17 -13
- package/dist/generated/ast.js +15 -5
- package/dist/generated/grammar.js +1519 -1360
- package/dist/index.d.ts +1 -0
- package/dist/index.js +0 -1
- package/dist/lsp/DocumentSymbolProvider.js +20 -10
- package/dist/lsp/HoverProvider.js +1 -4
- package/dist/lsp/SemanticTokenProvider.js +42 -70
- package/dist/lsp/index.d.ts +0 -1
- package/dist/lsp/index.js +0 -1
- package/dist/model/fqn-index.js +7 -5
- package/dist/model/model-builder.js +9 -8
- package/dist/module.js +11 -7
- package/dist/references/scope-provider.d.ts +2 -2
- package/dist/references/scope-provider.js +4 -4
- package/dist/{lsp → shared}/CodeLensProvider.js +2 -2
- package/dist/shared/WorkspaceManager.d.ts +13 -0
- package/dist/shared/WorkspaceManager.js +19 -0
- package/dist/shared/index.d.ts +2 -0
- package/dist/shared/index.js +2 -0
- package/dist/test/testServices.js +4 -0
- package/dist/validation/element.js +2 -2
- package/dist/validation/index.js +3 -1
- package/dist/validation/relation.d.ts +4 -0
- package/dist/validation/relation.js +53 -0
- package/dist/validation/specification.js +6 -4
- package/dist/validation/view.js +2 -1
- package/package.json +21 -8
- /package/dist/{lsp → shared}/CodeLensProvider.d.ts +0 -0
package/dist/index.d.ts
CHANGED
package/dist/index.js
CHANGED
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
// import { type DefaultSharedModuleContext, startLanguageServer as startLangiumLanguageServer } from 'langium'
|
|
2
2
|
export { createLanguageServices } from './module';
|
|
3
|
-
// export type { C4XServices }
|
|
4
3
|
// export type { C4XModel } from './c4x-model'
|
|
5
4
|
// export type { C4XLangiumDocument } from './ast'
|
|
6
5
|
// export {
|
|
@@ -56,13 +56,15 @@ export class LikeC4DocumentSymbolProvider {
|
|
|
56
56
|
}
|
|
57
57
|
if (specSymbols.length === 0)
|
|
58
58
|
return [];
|
|
59
|
-
return [
|
|
59
|
+
return [
|
|
60
|
+
{
|
|
60
61
|
kind: SymbolKind.Class,
|
|
61
62
|
name: astSpec.name,
|
|
62
63
|
range: cstModel.range,
|
|
63
64
|
selectionRange: specKeywordNode.range,
|
|
64
65
|
children: specSymbols
|
|
65
|
-
}
|
|
66
|
+
}
|
|
67
|
+
];
|
|
66
68
|
};
|
|
67
69
|
getModelSymbols = (astModel) => {
|
|
68
70
|
const cstModel = astModel?.$cstNode;
|
|
@@ -71,13 +73,15 @@ export class LikeC4DocumentSymbolProvider {
|
|
|
71
73
|
const nameNode = findNodeForProperty(cstModel, 'name');
|
|
72
74
|
if (!nameNode)
|
|
73
75
|
return [];
|
|
74
|
-
return [
|
|
76
|
+
return [
|
|
77
|
+
{
|
|
75
78
|
kind: SymbolKind.Class,
|
|
76
79
|
name: astModel.name,
|
|
77
80
|
range: cstModel.range,
|
|
78
81
|
selectionRange: nameNode.range,
|
|
79
82
|
children: astModel.elements.flatMap(this.getElementsSymbol)
|
|
80
|
-
}
|
|
83
|
+
}
|
|
84
|
+
];
|
|
81
85
|
};
|
|
82
86
|
getElementsSymbol = (el) => {
|
|
83
87
|
if (ast.isExtendElement(el)) {
|
|
@@ -93,13 +97,15 @@ export class LikeC4DocumentSymbolProvider {
|
|
|
93
97
|
const nameNode = astElement.element.$cstNode;
|
|
94
98
|
if (!cst || !nameNode)
|
|
95
99
|
return [];
|
|
96
|
-
return [
|
|
100
|
+
return [
|
|
101
|
+
{
|
|
97
102
|
kind: SymbolKind.Constructor,
|
|
98
103
|
name: nameNode.text,
|
|
99
104
|
range: cst.range,
|
|
100
105
|
selectionRange: nameNode.range,
|
|
101
106
|
children: astElement.body.elements.flatMap(this.getElementsSymbol)
|
|
102
|
-
}
|
|
107
|
+
}
|
|
108
|
+
];
|
|
103
109
|
};
|
|
104
110
|
getElementSymbol = (astElement) => {
|
|
105
111
|
const cst = astElement.$cstNode;
|
|
@@ -112,14 +118,16 @@ export class LikeC4DocumentSymbolProvider {
|
|
|
112
118
|
const kind = astElement.kind.$refText;
|
|
113
119
|
// TODO: return the title as well
|
|
114
120
|
const detail = kind; // + (astElement.title ? ': ' + astElement.title : '').replaceAll('\n', ' ').trim()
|
|
115
|
-
return [
|
|
121
|
+
return [
|
|
122
|
+
{
|
|
116
123
|
kind: SymbolKind.Constructor,
|
|
117
124
|
name: name,
|
|
118
125
|
range: cst.range,
|
|
119
126
|
selectionRange: nameNode.range,
|
|
120
127
|
detail,
|
|
121
128
|
children: astElement.body?.elements.flatMap(this.getElementsSymbol) ?? []
|
|
122
|
-
}
|
|
129
|
+
}
|
|
130
|
+
];
|
|
123
131
|
};
|
|
124
132
|
getModelViewsSymbols = (astViews) => {
|
|
125
133
|
const cst = astViews?.$cstNode;
|
|
@@ -128,12 +136,14 @@ export class LikeC4DocumentSymbolProvider {
|
|
|
128
136
|
const nameNode = findNodeForProperty(cst, 'name');
|
|
129
137
|
if (!nameNode)
|
|
130
138
|
return [];
|
|
131
|
-
return [
|
|
139
|
+
return [
|
|
140
|
+
{
|
|
132
141
|
kind: SymbolKind.Class,
|
|
133
142
|
name: astViews.name,
|
|
134
143
|
range: cst.range,
|
|
135
144
|
selectionRange: nameNode.range,
|
|
136
145
|
children: []
|
|
137
|
-
}
|
|
146
|
+
}
|
|
147
|
+
];
|
|
138
148
|
};
|
|
139
149
|
}
|
|
@@ -35,10 +35,7 @@ export class LikeC4HoverProvider extends AstNodeHoverProvider {
|
|
|
35
35
|
if (!el) {
|
|
36
36
|
return;
|
|
37
37
|
}
|
|
38
|
-
const lines = [
|
|
39
|
-
el.id,
|
|
40
|
-
`${el.kind}: **${el.title}**`
|
|
41
|
-
];
|
|
38
|
+
const lines = [el.id, `${el.kind}: **${el.title}**`];
|
|
42
39
|
if (el.tags && el.tags.length > 0) {
|
|
43
40
|
lines.push(' \n', el.tags.map(t => '#' + t).join(', '));
|
|
44
41
|
}
|
|
@@ -7,25 +7,16 @@ export class LikeC4SemanticTokenProvider extends AbstractSemanticTokenProvider {
|
|
|
7
7
|
const keyword = (keyword, _index) => acceptor({
|
|
8
8
|
node,
|
|
9
9
|
keyword,
|
|
10
|
-
type: SemanticTokenTypes.keyword
|
|
10
|
+
type: SemanticTokenTypes.keyword
|
|
11
11
|
});
|
|
12
12
|
if (ast.isElementRef(node) || ast.isStrictElementRef(node)) {
|
|
13
13
|
acceptor({
|
|
14
14
|
node,
|
|
15
15
|
property: 'el',
|
|
16
|
-
type: isElementRefHead(node) ? SemanticTokenTypes.variable : SemanticTokenTypes.property
|
|
16
|
+
type: isElementRefHead(node) ? SemanticTokenTypes.variable : SemanticTokenTypes.property
|
|
17
17
|
});
|
|
18
|
-
// acceptor({
|
|
19
|
-
// node,
|
|
20
|
-
// property: 'el',
|
|
21
|
-
// type: SemanticTokenTypes.variable,
|
|
22
|
-
// })
|
|
23
18
|
return;
|
|
24
19
|
}
|
|
25
|
-
// if (ast.isSpec(node)) {
|
|
26
|
-
// keyword('spec')
|
|
27
|
-
// return
|
|
28
|
-
// }
|
|
29
20
|
if (ast.isWildcardExpression(node)) {
|
|
30
21
|
acceptor({
|
|
31
22
|
node,
|
|
@@ -34,7 +25,9 @@ export class LikeC4SemanticTokenProvider extends AbstractSemanticTokenProvider {
|
|
|
34
25
|
});
|
|
35
26
|
return;
|
|
36
27
|
}
|
|
37
|
-
if (ast.isRelationExpression(node) ||
|
|
28
|
+
if (ast.isRelationExpression(node) ||
|
|
29
|
+
ast.isIncomingExpression(node) ||
|
|
30
|
+
ast.isOutgoingExpression(node)) {
|
|
38
31
|
keyword('->');
|
|
39
32
|
return;
|
|
40
33
|
}
|
|
@@ -54,29 +47,12 @@ export class LikeC4SemanticTokenProvider extends AbstractSemanticTokenProvider {
|
|
|
54
47
|
}
|
|
55
48
|
return;
|
|
56
49
|
}
|
|
57
|
-
// if (ast.isDynamicViewStep(node)) {
|
|
58
|
-
// keyword(node.isReverse ? '<-' : '->')
|
|
59
|
-
// if (hasTitle(node)) {
|
|
60
|
-
// acceptor({
|
|
61
|
-
// node,
|
|
62
|
-
// property: 'title',
|
|
63
|
-
// type: SemanticTokenTypes.string
|
|
64
|
-
// })
|
|
65
|
-
// }
|
|
66
|
-
// return
|
|
67
|
-
// }
|
|
68
|
-
// if (ast.isStyleProperties(node)) {
|
|
69
|
-
// keyword('style')
|
|
70
|
-
// return
|
|
71
|
-
// }
|
|
72
50
|
if (ast.isElementKind(node)) {
|
|
73
51
|
acceptor({
|
|
74
52
|
node,
|
|
75
53
|
property: 'name',
|
|
76
54
|
type: SemanticTokenTypes.type,
|
|
77
|
-
modifier: [
|
|
78
|
-
SemanticTokenModifiers.definition,
|
|
79
|
-
]
|
|
55
|
+
modifier: [SemanticTokenModifiers.definition]
|
|
80
56
|
});
|
|
81
57
|
return;
|
|
82
58
|
}
|
|
@@ -122,11 +98,11 @@ export class LikeC4SemanticTokenProvider extends AbstractSemanticTokenProvider {
|
|
|
122
98
|
});
|
|
123
99
|
return;
|
|
124
100
|
}
|
|
125
|
-
if (ast.
|
|
101
|
+
if (ast.isAStyleProperty(node)) {
|
|
126
102
|
acceptor({
|
|
127
103
|
node,
|
|
128
104
|
property: 'key',
|
|
129
|
-
type: SemanticTokenTypes.keyword
|
|
105
|
+
type: SemanticTokenTypes.keyword
|
|
130
106
|
});
|
|
131
107
|
acceptor({
|
|
132
108
|
node,
|
|
@@ -135,36 +111,34 @@ export class LikeC4SemanticTokenProvider extends AbstractSemanticTokenProvider {
|
|
|
135
111
|
});
|
|
136
112
|
return;
|
|
137
113
|
}
|
|
138
|
-
if (ast.
|
|
114
|
+
if (ast.isAnyStringProperty(node)) {
|
|
139
115
|
acceptor({
|
|
140
116
|
node,
|
|
141
117
|
property: 'key',
|
|
142
|
-
type: SemanticTokenTypes.keyword
|
|
118
|
+
type: SemanticTokenTypes.keyword
|
|
119
|
+
});
|
|
120
|
+
acceptor({
|
|
121
|
+
node,
|
|
122
|
+
property: 'value',
|
|
123
|
+
type: SemanticTokenTypes.string
|
|
143
124
|
});
|
|
144
|
-
if ('value' in node) {
|
|
145
|
-
acceptor({
|
|
146
|
-
node,
|
|
147
|
-
property: 'value',
|
|
148
|
-
type: SemanticTokenTypes.string
|
|
149
|
-
});
|
|
150
|
-
}
|
|
151
|
-
return;
|
|
152
|
-
}
|
|
153
|
-
if (ast.isModel(node)) {
|
|
154
|
-
keyword('model');
|
|
155
|
-
return;
|
|
156
|
-
}
|
|
157
|
-
if (ast.isModelViews(node)) {
|
|
158
|
-
keyword('views');
|
|
159
125
|
return;
|
|
160
126
|
}
|
|
127
|
+
// if (ast.isModel(node)) {
|
|
128
|
+
// keyword('model')
|
|
129
|
+
// return
|
|
130
|
+
// }
|
|
131
|
+
// if (ast.isModelViews(node)) {
|
|
132
|
+
// keyword('views')
|
|
133
|
+
// return
|
|
134
|
+
// }
|
|
161
135
|
if (ast.isElement(node)) {
|
|
162
136
|
return this.highlightAstElement(node, acceptor);
|
|
163
137
|
}
|
|
164
|
-
if (ast.isExtendElement(node)) {
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
}
|
|
138
|
+
// if (ast.isExtendElement(node)) {
|
|
139
|
+
// keyword('extend')
|
|
140
|
+
// return
|
|
141
|
+
// }
|
|
168
142
|
// if (ast.isElementProperty(node) || ast.isRelationProperty(node) || ast.isViewProperty(node)) {
|
|
169
143
|
// acceptor({
|
|
170
144
|
// node,
|
|
@@ -188,28 +162,26 @@ export class LikeC4SemanticTokenProvider extends AbstractSemanticTokenProvider {
|
|
|
188
162
|
// keyword('steps')
|
|
189
163
|
// return
|
|
190
164
|
// }
|
|
191
|
-
if (ast.isViewRuleAutoLayout(node)) {
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
}
|
|
195
|
-
if (ast.isViewRuleStyle(node)) {
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
}
|
|
199
|
-
if (ast.isViewRuleExpression(node)) {
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
}
|
|
203
|
-
//
|
|
165
|
+
// if (ast.isViewRuleAutoLayout(node)) {
|
|
166
|
+
// keyword('autoLayout')
|
|
167
|
+
// return
|
|
168
|
+
// }
|
|
169
|
+
// if (ast.isViewRuleStyle(node)) {
|
|
170
|
+
// keyword('style')
|
|
171
|
+
// return
|
|
172
|
+
// }
|
|
173
|
+
// if (ast.isViewRuleExpression(node)) {
|
|
174
|
+
// keyword(node.isInclude ? 'include' : 'exclude')
|
|
175
|
+
// return
|
|
176
|
+
// }
|
|
177
|
+
// //
|
|
204
178
|
}
|
|
205
179
|
highlightAstElement(node, acceptor) {
|
|
206
180
|
acceptor({
|
|
207
181
|
node,
|
|
208
182
|
property: 'name',
|
|
209
183
|
type: SemanticTokenTypes.variable,
|
|
210
|
-
modifier: [
|
|
211
|
-
SemanticTokenModifiers.declaration,
|
|
212
|
-
]
|
|
184
|
+
modifier: [SemanticTokenModifiers.declaration]
|
|
213
185
|
});
|
|
214
186
|
acceptor({
|
|
215
187
|
node,
|
|
@@ -230,7 +202,7 @@ export class LikeC4SemanticTokenProvider extends AbstractSemanticTokenProvider {
|
|
|
230
202
|
acceptor({
|
|
231
203
|
node,
|
|
232
204
|
property: 'name',
|
|
233
|
-
type: SemanticTokenTypes.variable
|
|
205
|
+
type: SemanticTokenTypes.variable
|
|
234
206
|
});
|
|
235
207
|
}
|
|
236
208
|
if (node.viewOf) {
|
package/dist/lsp/index.d.ts
CHANGED
package/dist/lsp/index.js
CHANGED
package/dist/model/fqn-index.js
CHANGED
|
@@ -42,7 +42,7 @@ export class FqnIndex {
|
|
|
42
42
|
directChildrenOf(parent) {
|
|
43
43
|
return this.#index
|
|
44
44
|
.entriesGroupedByKey()
|
|
45
|
-
.flatMap(([fqn, descrs]) => (descrs.length === 1 && parentFqn(fqn) === parent
|
|
45
|
+
.flatMap(([fqn, descrs]) => (descrs.length === 1 && parentFqn(fqn) === parent ? descrs : []));
|
|
46
46
|
}
|
|
47
47
|
uniqueDescedants(parent) {
|
|
48
48
|
return new StreamImpl(() => {
|
|
@@ -61,7 +61,7 @@ export class FqnIndex {
|
|
|
61
61
|
}
|
|
62
62
|
}
|
|
63
63
|
});
|
|
64
|
-
if (
|
|
64
|
+
if (children.length + descedants.length === 0) {
|
|
65
65
|
return null;
|
|
66
66
|
}
|
|
67
67
|
const nested = new MultiMap(children.map(([_fqn, desc]) => [desc.name, desc]));
|
|
@@ -72,9 +72,9 @@ export class FqnIndex {
|
|
|
72
72
|
}
|
|
73
73
|
return nested
|
|
74
74
|
.entriesGroupedByKey()
|
|
75
|
-
.flatMap(([_name, descrs]) => descrs.length === 1 ? descrs : [])
|
|
75
|
+
.flatMap(([_name, descrs]) => (descrs.length === 1 ? descrs : []))
|
|
76
76
|
.iterator();
|
|
77
|
-
},
|
|
77
|
+
}, iterator => {
|
|
78
78
|
if (iterator) {
|
|
79
79
|
return iterator.next();
|
|
80
80
|
}
|
|
@@ -128,7 +128,9 @@ export class FqnIndex {
|
|
|
128
128
|
}
|
|
129
129
|
cleanIndexedElements(docUri) {
|
|
130
130
|
const docUriAsString = docUri.toString();
|
|
131
|
-
const toDelete = this.#index
|
|
131
|
+
const toDelete = this.#index
|
|
132
|
+
.entries()
|
|
133
|
+
.filter(([, indexed]) => indexed.documentUri.toString() === docUriAsString);
|
|
132
134
|
for (const [fqn, indexed] of toDelete.toArray()) {
|
|
133
135
|
this.#index.delete(fqn, indexed);
|
|
134
136
|
}
|
|
@@ -6,6 +6,7 @@ import { DocumentState, getDocument, interruptAndCheck } from 'langium';
|
|
|
6
6
|
import objectHash from 'object-hash';
|
|
7
7
|
import { clone, isNil, mergeDeepRight, omit, reduce } from 'rambdax';
|
|
8
8
|
import invariant from 'tiny-invariant';
|
|
9
|
+
import { toAutoLayout } from '../ast';
|
|
9
10
|
import { ElementViewOps, ast, c4hash, cleanParsedModel, isLikeC4LangiumDocument, isParsedLikeC4LangiumDocument, resolveRelationPoints, streamModel, toElementStyle } from '../ast';
|
|
10
11
|
import { elementRef, strictElementRefFqn } from '../elementRef';
|
|
11
12
|
import { logger } from '../logger';
|
|
@@ -67,7 +68,7 @@ export class LikeC4ModelBuilder {
|
|
|
67
68
|
return {
|
|
68
69
|
...(kind.shape !== DefaultElementShape ? { shape: kind.shape } : {}),
|
|
69
70
|
...(kind.color !== DefaultThemeColor ? { color: kind.color } : {}),
|
|
70
|
-
...
|
|
71
|
+
...omit(['astPath'], el)
|
|
71
72
|
};
|
|
72
73
|
}
|
|
73
74
|
return null;
|
|
@@ -127,7 +128,7 @@ export class LikeC4ModelBuilder {
|
|
|
127
128
|
const styleProps = toElementStyle(style?.props);
|
|
128
129
|
specification.kinds[kind.name] = {
|
|
129
130
|
color: styleProps.color ?? DefaultThemeColor,
|
|
130
|
-
shape: styleProps.shape ?? DefaultElementShape
|
|
131
|
+
shape: styleProps.shape ?? DefaultElementShape
|
|
131
132
|
};
|
|
132
133
|
}
|
|
133
134
|
catch (e) {
|
|
@@ -181,7 +182,7 @@ export class LikeC4ModelBuilder {
|
|
|
181
182
|
const styleProps = astNode.body?.props.find(ast.isElementStyleProperty)?.props;
|
|
182
183
|
const { color, shape } = toElementStyle(styleProps);
|
|
183
184
|
const astPath = this.getAstNodePath(astNode);
|
|
184
|
-
let [title, description, technology
|
|
185
|
+
let [title, description, technology] = astNode.props;
|
|
185
186
|
const bodyProps = astNode.body?.props.filter((p) => ast.isElementStringProperty(p)) ?? [];
|
|
186
187
|
title = title ?? bodyProps.find(p => p.key === 'title')?.value;
|
|
187
188
|
description = description ?? bodyProps.find(p => p.key === 'description')?.value;
|
|
@@ -195,7 +196,7 @@ export class LikeC4ModelBuilder {
|
|
|
195
196
|
...(description && { description }),
|
|
196
197
|
...(tags.length > 0 ? { tags } : {}),
|
|
197
198
|
...(shape && shape !== DefaultElementShape ? { shape } : {}),
|
|
198
|
-
...(color && color !== DefaultThemeColor ? { color } : {})
|
|
199
|
+
...(color && color !== DefaultThemeColor ? { color } : {})
|
|
199
200
|
};
|
|
200
201
|
}
|
|
201
202
|
parseRelation(astNode) {
|
|
@@ -208,11 +209,11 @@ export class LikeC4ModelBuilder {
|
|
|
208
209
|
target
|
|
209
210
|
};
|
|
210
211
|
const id = objectHash(hashdata);
|
|
211
|
-
const title = astNode.definition?.props.find(p => p.key === 'title')?.value ?? '';
|
|
212
|
+
const title = astNode.title ?? astNode.definition?.props.find(p => p.key === 'title')?.value ?? '';
|
|
212
213
|
return {
|
|
213
214
|
id,
|
|
214
215
|
...hashdata,
|
|
215
|
-
title
|
|
216
|
+
title
|
|
216
217
|
};
|
|
217
218
|
}
|
|
218
219
|
parseElementExpression(astNode) {
|
|
@@ -253,7 +254,7 @@ export class LikeC4ModelBuilder {
|
|
|
253
254
|
if (ast.isRelationExpression(astNode)) {
|
|
254
255
|
return {
|
|
255
256
|
source: this.parseElementExpression(astNode.source),
|
|
256
|
-
target: this.parseElementExpression(astNode.target)
|
|
257
|
+
target: this.parseElementExpression(astNode.target)
|
|
257
258
|
};
|
|
258
259
|
}
|
|
259
260
|
failExpectedNever(astNode);
|
|
@@ -277,7 +278,7 @@ export class LikeC4ModelBuilder {
|
|
|
277
278
|
}
|
|
278
279
|
if (ast.isViewRuleAutoLayout(astNode)) {
|
|
279
280
|
return {
|
|
280
|
-
autoLayout: astNode.direction
|
|
281
|
+
autoLayout: toAutoLayout(astNode.direction)
|
|
281
282
|
};
|
|
282
283
|
}
|
|
283
284
|
failExpectedNever(astNode);
|
package/dist/module.js
CHANGED
|
@@ -1,10 +1,11 @@
|
|
|
1
|
-
import { createDefaultModule,
|
|
1
|
+
import { createDefaultModule, createDefaultSharedModule, inject } from 'langium';
|
|
2
2
|
import { LikeC4GeneratedModule, LikeC4GeneratedSharedModule } from './generated/module';
|
|
3
|
-
import {
|
|
3
|
+
import { LikeC4DocumentSymbolProvider, LikeC4HoverProvider, LikeC4SemanticTokenProvider } from './lsp';
|
|
4
4
|
import { FqnIndex, LikeC4ModelBuilder, LikeC4ModelLocator } from './model';
|
|
5
|
-
import {
|
|
6
|
-
import { LikeC4CodeLensProvider, LikeC4DocumentSymbolProvider, LikeC4HoverProvider, LikeC4SemanticTokenProvider } from './lsp';
|
|
5
|
+
import { LikeC4ScopeComputation, LikeC4ScopeProvider } from './references';
|
|
7
6
|
import { registerProtocolHandlers } from './registerProtocolHandlers';
|
|
7
|
+
import { LikeC4CodeLensProvider, LikeC4WorkspaceManager } from './shared';
|
|
8
|
+
import { registerValidationChecks } from './validation';
|
|
8
9
|
function bind(Type) {
|
|
9
10
|
return (services) => new Type(services);
|
|
10
11
|
}
|
|
@@ -12,7 +13,7 @@ export const LikeC4Module = {
|
|
|
12
13
|
likec4: {
|
|
13
14
|
FqnIndex: bind(FqnIndex),
|
|
14
15
|
ModelBuilder: bind(LikeC4ModelBuilder),
|
|
15
|
-
ModelLocator: bind(LikeC4ModelLocator)
|
|
16
|
+
ModelLocator: bind(LikeC4ModelLocator)
|
|
16
17
|
// Model: bind(LikeC4Model),
|
|
17
18
|
// Model: bind(LikeC4Model),
|
|
18
19
|
// SpecIndex: bind(LikeC4SpecIndex),
|
|
@@ -21,7 +22,7 @@ export const LikeC4Module = {
|
|
|
21
22
|
lsp: {
|
|
22
23
|
DocumentSymbolProvider: bind(LikeC4DocumentSymbolProvider),
|
|
23
24
|
SemanticTokenProvider: bind(LikeC4SemanticTokenProvider),
|
|
24
|
-
HoverProvider: bind(LikeC4HoverProvider)
|
|
25
|
+
HoverProvider: bind(LikeC4HoverProvider)
|
|
25
26
|
},
|
|
26
27
|
//
|
|
27
28
|
// // Formatter: bind(LikeC4Formatter),
|
|
@@ -34,8 +35,11 @@ export const LikeC4Module = {
|
|
|
34
35
|
};
|
|
35
36
|
const LikeC4SharedModule = {
|
|
36
37
|
...LikeC4GeneratedSharedModule,
|
|
38
|
+
workspace: {
|
|
39
|
+
WorkspaceManager: services => new LikeC4WorkspaceManager(services)
|
|
40
|
+
},
|
|
37
41
|
lsp: {
|
|
38
|
-
CodeLensProvider:
|
|
42
|
+
CodeLensProvider: services => new LikeC4CodeLensProvider(services)
|
|
39
43
|
}
|
|
40
44
|
};
|
|
41
45
|
export function createLanguageServices(context) {
|
|
@@ -9,7 +9,7 @@ export declare class LikeC4ScopeProvider extends DefaultScopeProvider {
|
|
|
9
9
|
getScope(context: ReferenceInfo): Scope;
|
|
10
10
|
protected computeScope(node: AstNode, referenceType: string): Scope;
|
|
11
11
|
/**
|
|
12
|
-
|
|
13
|
-
|
|
12
|
+
* Create a global scope filtered for the given reference type.
|
|
13
|
+
*/
|
|
14
14
|
protected getGlobalScope(referenceType: string): Scope;
|
|
15
15
|
}
|
|
@@ -19,7 +19,7 @@ export class LikeC4ScopeProvider extends DefaultScopeProvider {
|
|
|
19
19
|
return this.fqnIndex.uniqueDescedants(fqn).iterator();
|
|
20
20
|
}
|
|
21
21
|
return null;
|
|
22
|
-
},
|
|
22
|
+
}, iterator => {
|
|
23
23
|
if (iterator) {
|
|
24
24
|
return iterator.next();
|
|
25
25
|
}
|
|
@@ -37,7 +37,7 @@ export class LikeC4ScopeProvider extends DefaultScopeProvider {
|
|
|
37
37
|
return this.fqnIndex.uniqueDescedants(fqn).iterator();
|
|
38
38
|
}
|
|
39
39
|
return null;
|
|
40
|
-
},
|
|
40
|
+
}, iterator => {
|
|
41
41
|
if (iterator) {
|
|
42
42
|
return iterator.next();
|
|
43
43
|
}
|
|
@@ -102,8 +102,8 @@ export class LikeC4ScopeProvider extends DefaultScopeProvider {
|
|
|
102
102
|
}, this.getGlobalScope(referenceType));
|
|
103
103
|
}
|
|
104
104
|
/**
|
|
105
|
-
|
|
106
|
-
|
|
105
|
+
* Create a global scope filtered for the given reference type.
|
|
106
|
+
*/
|
|
107
107
|
getGlobalScope(referenceType) {
|
|
108
108
|
return new StreamScope(this.indexManager.allElements(referenceType));
|
|
109
109
|
}
|
|
@@ -9,7 +9,7 @@ export class LikeC4CodeLensProvider {
|
|
|
9
9
|
if (!isParsedLikeC4LangiumDocument(doc)) {
|
|
10
10
|
return;
|
|
11
11
|
}
|
|
12
|
-
return doc.parseResult.value.views?.views.flatMap(
|
|
12
|
+
return doc.parseResult.value.views?.views.flatMap(ast => {
|
|
13
13
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
14
14
|
const viewId = ElementViewOps.readId(ast);
|
|
15
15
|
const range = ast.$cstNode?.range;
|
|
@@ -27,7 +27,7 @@ export class LikeC4CodeLensProvider {
|
|
|
27
27
|
command: {
|
|
28
28
|
command: 'likec4.open-preview',
|
|
29
29
|
arguments: [viewId],
|
|
30
|
-
title: 'open preview'
|
|
30
|
+
title: 'open preview'
|
|
31
31
|
}
|
|
32
32
|
};
|
|
33
33
|
});
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import type { LangiumDocument, LangiumDocumentFactory, LangiumSharedServices } from 'langium';
|
|
2
|
+
import { DefaultWorkspaceManager } from 'langium';
|
|
3
|
+
import type { WorkspaceFolder } from 'vscode-languageserver-protocol';
|
|
4
|
+
export declare class LikeC4WorkspaceManager extends DefaultWorkspaceManager {
|
|
5
|
+
protected readonly documentFactory: LangiumDocumentFactory;
|
|
6
|
+
constructor(services: LangiumSharedServices);
|
|
7
|
+
/**
|
|
8
|
+
* Load all additional documents that shall be visible in the context of the given workspace
|
|
9
|
+
* folders and add them to the collector. This can be used to include built-in libraries of
|
|
10
|
+
* your language, which can be either loaded from provided files or constructed in memory.
|
|
11
|
+
*/
|
|
12
|
+
protected loadAdditionalDocuments(folders: WorkspaceFolder[], collector: (document: LangiumDocument) => void): Promise<void>;
|
|
13
|
+
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { DefaultWorkspaceManager } from 'langium';
|
|
2
|
+
import { URI } from 'vscode-uri';
|
|
3
|
+
import * as builtin from '../builtin';
|
|
4
|
+
export class LikeC4WorkspaceManager extends DefaultWorkspaceManager {
|
|
5
|
+
documentFactory;
|
|
6
|
+
constructor(services) {
|
|
7
|
+
super(services);
|
|
8
|
+
this.documentFactory = services.workspace.LangiumDocumentFactory;
|
|
9
|
+
}
|
|
10
|
+
/**
|
|
11
|
+
* Load all additional documents that shall be visible in the context of the given workspace
|
|
12
|
+
* folders and add them to the collector. This can be used to include built-in libraries of
|
|
13
|
+
* your language, which can be either loaded from provided files or constructed in memory.
|
|
14
|
+
*/
|
|
15
|
+
loadAdditionalDocuments(folders, collector) {
|
|
16
|
+
collector(this.documentFactory.fromString(builtin.specification.document, URI.parse(builtin.specification.uri)));
|
|
17
|
+
return Promise.resolve();
|
|
18
|
+
}
|
|
19
|
+
}
|
|
@@ -7,8 +7,10 @@ export function createTestServices() {
|
|
|
7
7
|
const langiumDocuments = services.shared.workspace.LangiumDocuments;
|
|
8
8
|
const documentBuilder = services.shared.workspace.DocumentBuilder;
|
|
9
9
|
const modelBuilder = services.likec4.ModelBuilder;
|
|
10
|
+
const initPromise = services.shared.workspace.WorkspaceManager.initializeWorkspace([]);
|
|
10
11
|
let documentIndex = 1;
|
|
11
12
|
const parse = async (input, uri) => {
|
|
13
|
+
await initPromise;
|
|
12
14
|
uri = uri ?? `${documentIndex++}${metaData.fileExtensions[0]}`;
|
|
13
15
|
const document = services.shared.workspace.LangiumDocumentFactory.fromString(input, URI.file(uri));
|
|
14
16
|
langiumDocuments.addDocument(document);
|
|
@@ -16,6 +18,7 @@ export function createTestServices() {
|
|
|
16
18
|
return document;
|
|
17
19
|
};
|
|
18
20
|
const validate = async (input) => {
|
|
21
|
+
await initPromise;
|
|
19
22
|
const document = typeof input === 'string' ? await parse(input) : input;
|
|
20
23
|
await documentBuilder.build([document], { validationChecks: 'all' });
|
|
21
24
|
const diagnostics = document.diagnostics ?? [];
|
|
@@ -27,6 +30,7 @@ export function createTestServices() {
|
|
|
27
30
|
};
|
|
28
31
|
};
|
|
29
32
|
const validateAll = async () => {
|
|
33
|
+
await initPromise;
|
|
30
34
|
const docs = langiumDocuments.all.toArray();
|
|
31
35
|
await documentBuilder.build(docs, { validationChecks: 'all' });
|
|
32
36
|
const diagnostics = docs.flatMap(doc => doc.diagnostics ?? []);
|
|
@@ -5,7 +5,7 @@ export const elementChecks = (services) => {
|
|
|
5
5
|
if (!fqn) {
|
|
6
6
|
accept('error', 'Not indexed', {
|
|
7
7
|
node: el,
|
|
8
|
-
property: 'name'
|
|
8
|
+
property: 'name'
|
|
9
9
|
});
|
|
10
10
|
return;
|
|
11
11
|
}
|
|
@@ -13,7 +13,7 @@ export const elementChecks = (services) => {
|
|
|
13
13
|
if (withSameFqn.length > 1) {
|
|
14
14
|
accept('error', `Duplicate element name ${el.name !== fqn ? el.name + ' (' + fqn + ')' : el.name}`, {
|
|
15
15
|
node: el,
|
|
16
|
-
property: 'name'
|
|
16
|
+
property: 'name'
|
|
17
17
|
});
|
|
18
18
|
}
|
|
19
19
|
};
|
package/dist/validation/index.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { elementChecks } from './element';
|
|
2
|
+
import { relationChecks } from './relation';
|
|
2
3
|
import { elementKindChecks, tagChecks } from './specification';
|
|
3
4
|
import { viewChecks } from './view';
|
|
4
5
|
export function registerValidationChecks(services) {
|
|
@@ -15,6 +16,7 @@ export function registerValidationChecks(services) {
|
|
|
15
16
|
ElementView: viewChecks(services),
|
|
16
17
|
Element: elementChecks(services),
|
|
17
18
|
ElementKind: elementKindChecks(services),
|
|
18
|
-
|
|
19
|
+
Relation: relationChecks(services),
|
|
20
|
+
Tag: tagChecks(services)
|
|
19
21
|
});
|
|
20
22
|
}
|