@likec4/language-server 0.5.0 → 0.6.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/contrib/likec4.monarch.ts +31 -0
- package/contrib/likec4.tmLanguage.json +73 -0
- package/dist/__test__/parser-smoke/01-Specification.d.ts +3 -0
- package/dist/__test__/parser-smoke/01-Specification.js +42 -0
- package/dist/__test__/parser-smoke/02-Model.d.ts +9 -0
- package/dist/__test__/parser-smoke/02-Model.js +110 -0
- package/dist/__test__/parser-smoke/03-ModelRelation.d.ts +6 -0
- package/dist/__test__/parser-smoke/03-ModelRelation.js +81 -0
- package/dist/__test__/parser-smoke/04-Scope.d.ts +2 -0
- package/dist/__test__/parser-smoke/04-Scope.js +38 -0
- package/dist/__test__/parser-smoke/05-StrictElementRef.d.ts +3 -0
- package/dist/__test__/parser-smoke/05-StrictElementRef.js +46 -0
- package/dist/__test__/parser-smoke/06-ElementRef.d.ts +2 -0
- package/dist/__test__/parser-smoke/06-ElementRef.js +59 -0
- package/dist/__test__/parser-smoke/07-Views.d.ts +10 -0
- package/dist/__test__/parser-smoke/07-Views.js +146 -0
- package/dist/__test__/parser-smoke/08-Structurizr.d.ts +1 -0
- package/dist/__test__/parser-smoke/08-Structurizr.js +22 -0
- package/dist/__test__/parser-smoke/index.d.ts +8 -0
- package/dist/__test__/parser-smoke/index.js +8 -0
- package/dist/__test__/parser-smoke-extendsElement.spec.d.ts +1 -0
- package/dist/__test__/parser-smoke-extendsElement.spec.js +36 -0
- package/dist/__test__/parser-smoke.spec.d.ts +1 -0
- package/dist/__test__/parser-smoke.spec.js +28 -0
- package/dist/ast.d.ts +1 -0
- package/dist/ast.js +16 -15
- package/dist/generated/ast.d.ts +16 -12
- package/dist/generated/ast.js +15 -5
- package/dist/generated/grammar.js +1534 -1379
- package/dist/index.d.ts +1 -1
- package/dist/index.js +0 -2
- package/dist/lsp/SemanticTokenProvider.js +32 -58
- package/dist/model/model-builder.js +13 -12
- package/dist/model/model-builder.spec.d.ts +1 -0
- package/dist/model/model-builder.spec.js +141 -0
- package/dist/protocol.d.ts +16 -12
- package/dist/protocol.js +2 -2
- package/dist/registerProtocolHandlers.js +24 -9
- package/dist/validation/element.spec.d.ts +1 -0
- package/dist/validation/element.spec.js +65 -0
- package/dist/validation/relation.spec.d.ts +1 -0
- package/dist/validation/relation.spec.js +93 -0
- package/dist/validation/specification.spec.d.ts +1 -0
- package/dist/validation/specification.spec.js +31 -0
- package/dist/validation/view.spec.d.ts +1 -0
- package/dist/validation/view.spec.js +20 -0
- package/package.json +22 -18
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 {
|
|
@@ -13,4 +12,3 @@ export { LikeC4LanguageMetaData as LanguageMetaData } from './generated/module';
|
|
|
13
12
|
// startLangiumLanguageServer(shared)
|
|
14
13
|
// return likec4
|
|
15
14
|
// }
|
|
16
|
-
export { Rpc } from './protocol';
|
|
@@ -15,17 +15,8 @@ export class LikeC4SemanticTokenProvider extends AbstractSemanticTokenProvider {
|
|
|
15
15
|
property: 'el',
|
|
16
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,
|
|
@@ -56,21 +47,6 @@ export class LikeC4SemanticTokenProvider extends AbstractSemanticTokenProvider {
|
|
|
56
47
|
}
|
|
57
48
|
return;
|
|
58
49
|
}
|
|
59
|
-
// if (ast.isDynamicViewStep(node)) {
|
|
60
|
-
// keyword(node.isReverse ? '<-' : '->')
|
|
61
|
-
// if (hasTitle(node)) {
|
|
62
|
-
// acceptor({
|
|
63
|
-
// node,
|
|
64
|
-
// property: 'title',
|
|
65
|
-
// type: SemanticTokenTypes.string
|
|
66
|
-
// })
|
|
67
|
-
// }
|
|
68
|
-
// return
|
|
69
|
-
// }
|
|
70
|
-
// if (ast.isStyleProperties(node)) {
|
|
71
|
-
// keyword('style')
|
|
72
|
-
// return
|
|
73
|
-
// }
|
|
74
50
|
if (ast.isElementKind(node)) {
|
|
75
51
|
acceptor({
|
|
76
52
|
node,
|
|
@@ -122,7 +98,7 @@ 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',
|
|
@@ -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
118
|
type: SemanticTokenTypes.keyword
|
|
143
119
|
});
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
});
|
|
150
|
-
}
|
|
151
|
-
return;
|
|
152
|
-
}
|
|
153
|
-
if (ast.isModel(node)) {
|
|
154
|
-
keyword('model');
|
|
155
|
-
return;
|
|
156
|
-
}
|
|
157
|
-
if (ast.isModelViews(node)) {
|
|
158
|
-
keyword('views');
|
|
120
|
+
acceptor({
|
|
121
|
+
node,
|
|
122
|
+
property: 'value',
|
|
123
|
+
type: SemanticTokenTypes.string
|
|
124
|
+
});
|
|
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,19 +162,19 @@ 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({
|
|
@@ -6,10 +6,11 @@ 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';
|
|
12
|
-
import { Rpc } from '
|
|
13
|
+
import { Rpc } from '@likec4/language-protocol';
|
|
13
14
|
import { failExpectedNever } from '../utils';
|
|
14
15
|
export class LikeC4ModelBuilder {
|
|
15
16
|
services;
|
|
@@ -258,29 +259,29 @@ export class LikeC4ModelBuilder {
|
|
|
258
259
|
}
|
|
259
260
|
failExpectedNever(astNode);
|
|
260
261
|
}
|
|
261
|
-
parseViewRule(
|
|
262
|
-
if (ast.isViewRuleExpression(
|
|
263
|
-
const exprs =
|
|
262
|
+
parseViewRule(astRule) {
|
|
263
|
+
if (ast.isViewRuleExpression(astRule)) {
|
|
264
|
+
const exprs = astRule.expressions.map(n => this.parseExpression(n));
|
|
264
265
|
return {
|
|
265
|
-
isInclude:
|
|
266
|
+
isInclude: astRule.isInclude,
|
|
266
267
|
exprs
|
|
267
268
|
};
|
|
268
269
|
}
|
|
269
|
-
if (ast.isViewRuleStyle(
|
|
270
|
-
const styleProps = toElementStyle(
|
|
270
|
+
if (ast.isViewRuleStyle(astRule)) {
|
|
271
|
+
const styleProps = toElementStyle(astRule.props);
|
|
271
272
|
return {
|
|
272
|
-
targets:
|
|
273
|
+
targets: astRule.targets.map(n => this.parseElementExpression(n)),
|
|
273
274
|
style: {
|
|
274
275
|
...styleProps
|
|
275
276
|
}
|
|
276
277
|
};
|
|
277
278
|
}
|
|
278
|
-
if (ast.isViewRuleAutoLayout(
|
|
279
|
+
if (ast.isViewRuleAutoLayout(astRule)) {
|
|
279
280
|
return {
|
|
280
|
-
autoLayout:
|
|
281
|
+
autoLayout: toAutoLayout(astRule.direction)
|
|
281
282
|
};
|
|
282
283
|
}
|
|
283
|
-
failExpectedNever(
|
|
284
|
+
failExpectedNever(astRule);
|
|
284
285
|
}
|
|
285
286
|
parseElementView(astNode) {
|
|
286
287
|
const viewOfEl = astNode.viewOf && elementRef(astNode.viewOf);
|
|
@@ -326,6 +327,6 @@ export class LikeC4ModelBuilder {
|
|
|
326
327
|
return;
|
|
327
328
|
}
|
|
328
329
|
logger.debug('Send onDidChangeModel');
|
|
329
|
-
await connection.sendNotification(Rpc.onDidChangeModel
|
|
330
|
+
await connection.sendNotification(Rpc.onDidChangeModel);
|
|
330
331
|
}
|
|
331
332
|
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
import { describe, expect, it } from 'vitest';
|
|
2
|
+
import { createTestServices } from '../test';
|
|
3
|
+
import { keys } from 'rambdax';
|
|
4
|
+
describe('LikeC4ModelBuilder', () => {
|
|
5
|
+
it('builds model', async () => {
|
|
6
|
+
const { validate, buildModel } = createTestServices();
|
|
7
|
+
const { diagnostics } = await validate(`
|
|
8
|
+
specification {
|
|
9
|
+
element component
|
|
10
|
+
element user {
|
|
11
|
+
style {
|
|
12
|
+
shape: person
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
tag deprecated
|
|
16
|
+
}
|
|
17
|
+
model {
|
|
18
|
+
user client {
|
|
19
|
+
-> frontend
|
|
20
|
+
}
|
|
21
|
+
component system {
|
|
22
|
+
backend = component 'Backend' {
|
|
23
|
+
technology 'NodeJS'
|
|
24
|
+
|
|
25
|
+
style {
|
|
26
|
+
color secondary
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
component frontend {
|
|
30
|
+
#deprecated
|
|
31
|
+
description 'Frontend description'
|
|
32
|
+
|
|
33
|
+
style {
|
|
34
|
+
color: muted
|
|
35
|
+
shape: browser
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
-> backend 'requests'
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
`);
|
|
43
|
+
expect(diagnostics).toHaveLength(0);
|
|
44
|
+
const model = await buildModel();
|
|
45
|
+
expect(model).toBeDefined();
|
|
46
|
+
expect(model.elements).toMatchObject({
|
|
47
|
+
client: {
|
|
48
|
+
kind: 'user',
|
|
49
|
+
shape: 'person'
|
|
50
|
+
},
|
|
51
|
+
'system.backend': {
|
|
52
|
+
color: 'secondary',
|
|
53
|
+
title: 'Backend',
|
|
54
|
+
technology: 'NodeJS'
|
|
55
|
+
},
|
|
56
|
+
'system.frontend': {
|
|
57
|
+
color: 'muted',
|
|
58
|
+
shape: 'browser',
|
|
59
|
+
description: 'Frontend description'
|
|
60
|
+
}
|
|
61
|
+
});
|
|
62
|
+
expect(model.elements['client']).not.toHaveProperty('color');
|
|
63
|
+
expect(model.elements['system']).not.toHaveProperty('color');
|
|
64
|
+
expect(model.elements['system']).not.toHaveProperty('shape');
|
|
65
|
+
expect(model.elements['system.backend']).toHaveProperty('color', 'secondary');
|
|
66
|
+
expect(model.elements['system.backend']).not.toHaveProperty('description');
|
|
67
|
+
expect(model).toMatchSnapshot();
|
|
68
|
+
});
|
|
69
|
+
it('builds model with extend', async () => {
|
|
70
|
+
const { parse, validateAll, buildModel } = createTestServices();
|
|
71
|
+
await parse(`
|
|
72
|
+
specification {
|
|
73
|
+
element component
|
|
74
|
+
element user
|
|
75
|
+
tag deprecated
|
|
76
|
+
}
|
|
77
|
+
model {
|
|
78
|
+
user client
|
|
79
|
+
component system {
|
|
80
|
+
backend = component
|
|
81
|
+
component frontend
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
`);
|
|
85
|
+
await parse(`
|
|
86
|
+
model {
|
|
87
|
+
extend system.backend {
|
|
88
|
+
component api
|
|
89
|
+
}
|
|
90
|
+
system.frontend -> api 'requests'
|
|
91
|
+
client -> system.frontend {
|
|
92
|
+
title 'opens'
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
views {
|
|
96
|
+
view index {
|
|
97
|
+
title 'Index'
|
|
98
|
+
include *
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
view v1 of api {
|
|
102
|
+
include *
|
|
103
|
+
autoLayout LeftRight
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
view of system.frontend {
|
|
107
|
+
include *
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
`);
|
|
111
|
+
const { errors } = await validateAll();
|
|
112
|
+
expect(errors).toEqual([]);
|
|
113
|
+
const model = await buildModel();
|
|
114
|
+
expect(model).toBeDefined();
|
|
115
|
+
expect(model.elements).toMatchObject({
|
|
116
|
+
client: {
|
|
117
|
+
kind: 'user'
|
|
118
|
+
},
|
|
119
|
+
'system.backend.api': {
|
|
120
|
+
kind: 'component'
|
|
121
|
+
}
|
|
122
|
+
});
|
|
123
|
+
expect(keys(model.relations)).toHaveLength(2);
|
|
124
|
+
expect(keys(model.views)).toHaveLength(3);
|
|
125
|
+
expect(model.views).toMatchObject({
|
|
126
|
+
index: {
|
|
127
|
+
id: 'index',
|
|
128
|
+
title: 'Index',
|
|
129
|
+
autoLayout: 'TB'
|
|
130
|
+
},
|
|
131
|
+
v1: {
|
|
132
|
+
id: 'v1',
|
|
133
|
+
viewOf: 'system.backend.api',
|
|
134
|
+
title: 'api',
|
|
135
|
+
autoLayout: 'LR'
|
|
136
|
+
}
|
|
137
|
+
});
|
|
138
|
+
expect(model.views['index']).not.toHaveProperty('viewOf');
|
|
139
|
+
expect(model).toMatchSnapshot();
|
|
140
|
+
});
|
|
141
|
+
});
|
package/dist/protocol.d.ts
CHANGED
|
@@ -4,32 +4,36 @@ import { NotificationType, RequestType0, RequestType } from 'vscode-languageserv
|
|
|
4
4
|
export declare const onDidChangeLikeC4Model: NotificationType<unknown>;
|
|
5
5
|
export declare const fetchLikeC4Model: RequestType0<{
|
|
6
6
|
model: LikeC4Model | null;
|
|
7
|
-
},
|
|
8
|
-
export declare const buildDocuments: RequestType<string[], void,
|
|
7
|
+
}, void>;
|
|
8
|
+
export declare const buildDocuments: RequestType<string[], void, void>;
|
|
9
9
|
export declare const locateElement: RequestType<{
|
|
10
10
|
element: Fqn;
|
|
11
|
-
property
|
|
12
|
-
},
|
|
11
|
+
property: string | null;
|
|
12
|
+
}, {
|
|
13
|
+
location: Location | null;
|
|
14
|
+
}, void>;
|
|
13
15
|
export declare const locateRelation: RequestType<{
|
|
14
16
|
id: RelationID;
|
|
15
|
-
}, Location | null,
|
|
17
|
+
}, Location | null, void>;
|
|
16
18
|
export declare const locateView: RequestType<{
|
|
17
19
|
id: ViewID;
|
|
18
|
-
}, Location | null,
|
|
20
|
+
}, Location | null, void>;
|
|
19
21
|
export declare const Rpc: {
|
|
20
22
|
readonly onDidChangeModel: NotificationType<unknown>;
|
|
21
23
|
readonly fetchModel: RequestType0<{
|
|
22
24
|
model: LikeC4Model | null;
|
|
23
|
-
},
|
|
24
|
-
readonly buildDocuments: RequestType<string[], void,
|
|
25
|
+
}, void>;
|
|
26
|
+
readonly buildDocuments: RequestType<string[], void, void>;
|
|
25
27
|
readonly locateElement: RequestType<{
|
|
26
28
|
element: Fqn;
|
|
27
|
-
property
|
|
28
|
-
},
|
|
29
|
+
property: string | null;
|
|
30
|
+
}, {
|
|
31
|
+
location: Location | null;
|
|
32
|
+
}, void>;
|
|
29
33
|
readonly locateRelation: RequestType<{
|
|
30
34
|
id: RelationID;
|
|
31
|
-
}, Location | null,
|
|
35
|
+
}, Location | null, void>;
|
|
32
36
|
readonly locateView: RequestType<{
|
|
33
37
|
id: ViewID;
|
|
34
|
-
}, Location | null,
|
|
38
|
+
}, Location | null, void>;
|
|
35
39
|
};
|
package/dist/protocol.js
CHANGED
|
@@ -2,13 +2,13 @@ import { NotificationType, RequestType0, RequestType } from 'vscode-languageserv
|
|
|
2
2
|
//#region From server
|
|
3
3
|
export const onDidChangeLikeC4Model = new NotificationType('likec4/onDidChangeModel');
|
|
4
4
|
//#endregion
|
|
5
|
-
|
|
5
|
+
//#region To server
|
|
6
6
|
export const fetchLikeC4Model = new RequestType0('likec4/fetchModel');
|
|
7
7
|
export const buildDocuments = new RequestType('likec4/buildDocuments');
|
|
8
8
|
export const locateElement = new RequestType('likec4/locateElement');
|
|
9
9
|
export const locateRelation = new RequestType('likec4/locateRelation');
|
|
10
10
|
export const locateView = new RequestType('likec4/locateView');
|
|
11
|
-
|
|
11
|
+
//#endregion
|
|
12
12
|
export const Rpc = {
|
|
13
13
|
onDidChangeModel: onDidChangeLikeC4Model,
|
|
14
14
|
fetchModel: fetchLikeC4Model,
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { logger } from './logger';
|
|
2
|
-
import {
|
|
2
|
+
import { buildDocuments, fetchLikeC4Model, locateElement, locateRelation, locateView } from '@likec4/language-protocol';
|
|
3
3
|
export function registerProtocolHandlers(services) {
|
|
4
4
|
const connection = services.shared.lsp.Connection;
|
|
5
5
|
if (!connection) {
|
|
@@ -8,7 +8,7 @@ export function registerProtocolHandlers(services) {
|
|
|
8
8
|
const modelBuilder = services.likec4.ModelBuilder;
|
|
9
9
|
const modelLocator = services.likec4.ModelLocator;
|
|
10
10
|
const LangiumDocuments = services.shared.workspace.LangiumDocuments;
|
|
11
|
-
connection.onRequest(
|
|
11
|
+
connection.onRequest(fetchLikeC4Model, async (_cancelToken) => {
|
|
12
12
|
let model;
|
|
13
13
|
try {
|
|
14
14
|
model = modelBuilder.buildModel() ?? null;
|
|
@@ -21,7 +21,7 @@ export function registerProtocolHandlers(services) {
|
|
|
21
21
|
model: model ?? null
|
|
22
22
|
});
|
|
23
23
|
});
|
|
24
|
-
connection.onRequest(
|
|
24
|
+
connection.onRequest(buildDocuments, async (docs, cancelToken) => {
|
|
25
25
|
const changed = [];
|
|
26
26
|
for (const d of docs) {
|
|
27
27
|
const uri = d;
|
|
@@ -37,13 +37,28 @@ export function registerProtocolHandlers(services) {
|
|
|
37
37
|
]`);
|
|
38
38
|
await services.shared.workspace.DocumentBuilder.update(changed, [], cancelToken);
|
|
39
39
|
});
|
|
40
|
-
connection.onRequest(
|
|
41
|
-
|
|
40
|
+
connection.onRequest(locateElement, async ({ element, property }, _cancelToken) => {
|
|
41
|
+
try {
|
|
42
|
+
return Promise.resolve(modelLocator.locateElement(element, property ?? 'name'));
|
|
43
|
+
}
|
|
44
|
+
catch (e) {
|
|
45
|
+
return Promise.reject(e);
|
|
46
|
+
}
|
|
42
47
|
});
|
|
43
|
-
connection.onRequest(
|
|
44
|
-
|
|
48
|
+
connection.onRequest(locateRelation, ({ id }, _cancelToken) => {
|
|
49
|
+
try {
|
|
50
|
+
return Promise.resolve(modelLocator.locateRelation(id));
|
|
51
|
+
}
|
|
52
|
+
catch (e) {
|
|
53
|
+
return Promise.reject(e);
|
|
54
|
+
}
|
|
45
55
|
});
|
|
46
|
-
connection.onRequest(
|
|
47
|
-
|
|
56
|
+
connection.onRequest(locateView, ({ id }, _cancelToken) => {
|
|
57
|
+
try {
|
|
58
|
+
return Promise.resolve(modelLocator.locateView(id));
|
|
59
|
+
}
|
|
60
|
+
catch (e) {
|
|
61
|
+
return Promise.reject(e);
|
|
62
|
+
}
|
|
48
63
|
});
|
|
49
64
|
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import { describe, expect, it } from 'vitest';
|
|
2
|
+
import { createTestServices } from '../test';
|
|
3
|
+
describe('elementChecks', () => {
|
|
4
|
+
it('should report duplicate element names', async () => {
|
|
5
|
+
const { validate } = createTestServices();
|
|
6
|
+
const { diagnostics } = await validate(`
|
|
7
|
+
specification {
|
|
8
|
+
element component
|
|
9
|
+
}
|
|
10
|
+
model {
|
|
11
|
+
component c1
|
|
12
|
+
component c2
|
|
13
|
+
component c1
|
|
14
|
+
}
|
|
15
|
+
`);
|
|
16
|
+
expect(diagnostics).toHaveLength(2);
|
|
17
|
+
for (const diagnostic of diagnostics) {
|
|
18
|
+
expect(diagnostic.severity, 'diagnostic severity').toBe(1);
|
|
19
|
+
expect(diagnostic.message, 'diagnostic message').toBe('Duplicate element name c1');
|
|
20
|
+
}
|
|
21
|
+
});
|
|
22
|
+
it('should report duplicate element names in extendElement', async () => {
|
|
23
|
+
const { parse, validateAll } = createTestServices();
|
|
24
|
+
await parse(`
|
|
25
|
+
specification {
|
|
26
|
+
element component
|
|
27
|
+
}
|
|
28
|
+
model {
|
|
29
|
+
component c1 {
|
|
30
|
+
component c2 {
|
|
31
|
+
component c3
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
`);
|
|
36
|
+
await parse(`
|
|
37
|
+
model {
|
|
38
|
+
extend c1.c2 {
|
|
39
|
+
component c3
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
`);
|
|
43
|
+
const { diagnostics } = await validateAll();
|
|
44
|
+
expect(diagnostics).toHaveLength(2);
|
|
45
|
+
for (const diagnostic of diagnostics) {
|
|
46
|
+
expect(diagnostic.severity, 'diagnostic severity').toBe(1);
|
|
47
|
+
expect(diagnostic.message, 'diagnostic message').toBe('Duplicate element name c3 (c1.c2.c3)');
|
|
48
|
+
}
|
|
49
|
+
});
|
|
50
|
+
it('should not report duplicate element names in nested', async () => {
|
|
51
|
+
const { validate } = createTestServices();
|
|
52
|
+
const { errors } = await validate(`
|
|
53
|
+
specification {
|
|
54
|
+
element component
|
|
55
|
+
}
|
|
56
|
+
model {
|
|
57
|
+
component c1
|
|
58
|
+
component c2 {
|
|
59
|
+
component c1
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
`);
|
|
63
|
+
expect(errors).toEqual([]);
|
|
64
|
+
});
|
|
65
|
+
});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
import { describe, expect, it } from 'vitest';
|
|
2
|
+
import { createTestServices } from '../test';
|
|
3
|
+
describe('relationChecks', () => {
|
|
4
|
+
it('should not report invalid relations', async () => {
|
|
5
|
+
const { validate } = createTestServices();
|
|
6
|
+
const { errors } = await validate(`
|
|
7
|
+
specification {
|
|
8
|
+
element component
|
|
9
|
+
}
|
|
10
|
+
model {
|
|
11
|
+
component c1 {
|
|
12
|
+
component c2 {
|
|
13
|
+
-> c3
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
component c3 {
|
|
17
|
+
this -> c1
|
|
18
|
+
}
|
|
19
|
+
c3 -> c2
|
|
20
|
+
}
|
|
21
|
+
`);
|
|
22
|
+
expect(errors).toEqual([]);
|
|
23
|
+
});
|
|
24
|
+
it('should report invalid relation: parent -> child', async () => {
|
|
25
|
+
const { validate } = createTestServices();
|
|
26
|
+
const { errors } = await validate(`
|
|
27
|
+
specification {
|
|
28
|
+
element component
|
|
29
|
+
}
|
|
30
|
+
model {
|
|
31
|
+
component c1 {
|
|
32
|
+
component c2 {
|
|
33
|
+
component c3
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
c1 -> c3
|
|
37
|
+
}
|
|
38
|
+
`);
|
|
39
|
+
expect(errors).toEqual(['Invalid relation (same hierarchy)']);
|
|
40
|
+
});
|
|
41
|
+
it('should report invalid relation: -> nested child', async () => {
|
|
42
|
+
const { validate } = createTestServices();
|
|
43
|
+
const { errors } = await validate(`
|
|
44
|
+
specification {
|
|
45
|
+
element component
|
|
46
|
+
}
|
|
47
|
+
model {
|
|
48
|
+
component c1 {
|
|
49
|
+
component c2 {
|
|
50
|
+
component c3
|
|
51
|
+
}
|
|
52
|
+
-> c3
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
`);
|
|
56
|
+
expect(errors).toEqual(['Invalid relation (same hierarchy)']);
|
|
57
|
+
});
|
|
58
|
+
it('should report invalid relation: child -> parent', async () => {
|
|
59
|
+
const { validate } = createTestServices();
|
|
60
|
+
const { errors } = await validate(`
|
|
61
|
+
specification {
|
|
62
|
+
element component
|
|
63
|
+
}
|
|
64
|
+
model {
|
|
65
|
+
component c1 {
|
|
66
|
+
component c2 {
|
|
67
|
+
component c3
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
c3 -> c2
|
|
71
|
+
}
|
|
72
|
+
`);
|
|
73
|
+
expect(errors).toEqual(['Invalid relation (same hierarchy)']);
|
|
74
|
+
});
|
|
75
|
+
it('should report invalid relation: nested child -> parent', async () => {
|
|
76
|
+
const { validate } = createTestServices();
|
|
77
|
+
const { errors } = await validate(`
|
|
78
|
+
specification {
|
|
79
|
+
element component
|
|
80
|
+
}
|
|
81
|
+
model {
|
|
82
|
+
component c1 {
|
|
83
|
+
component c2 {
|
|
84
|
+
component c3 {
|
|
85
|
+
-> c1
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
`);
|
|
91
|
+
expect(errors).toEqual(['Invalid relation (same hierarchy)']);
|
|
92
|
+
});
|
|
93
|
+
});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|