@likec4/language-server 0.6.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/index.d.ts +0 -1
- package/dist/index.js +0 -1
- package/dist/lsp/DocumentSymbolProvider.d.ts +1 -0
- package/dist/model/model-builder.js +12 -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.d.ts +1 -0
- 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 +17 -16
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
const model = `
|
|
2
|
+
specification {
|
|
3
|
+
element person
|
|
4
|
+
element group
|
|
5
|
+
element softwareSystem
|
|
6
|
+
element container
|
|
7
|
+
element component
|
|
8
|
+
}
|
|
9
|
+
`;
|
|
10
|
+
export const valid_08_Structurizr = model +
|
|
11
|
+
`
|
|
12
|
+
model {
|
|
13
|
+
u = person "User"
|
|
14
|
+
s = softwareSystem "Software System" {
|
|
15
|
+
webapp = container "Web Application" "" "Spring Boot"
|
|
16
|
+
database = container "Database" "" "Relational database schema"
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
u -> webapp "Uses"
|
|
20
|
+
webapp -> database "Reads from and writes to"
|
|
21
|
+
}
|
|
22
|
+
`;
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
export * from './01-Specification';
|
|
2
|
+
export * from './02-Model';
|
|
3
|
+
export * from './03-ModelRelation';
|
|
4
|
+
export * from './04-Scope';
|
|
5
|
+
export * from './05-StrictElementRef';
|
|
6
|
+
export * from './06-ElementRef';
|
|
7
|
+
export * from './07-Views';
|
|
8
|
+
export * from './08-Structurizr';
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
export * from './01-Specification';
|
|
2
|
+
export * from './02-Model';
|
|
3
|
+
export * from './03-ModelRelation';
|
|
4
|
+
export * from './04-Scope';
|
|
5
|
+
export * from './05-StrictElementRef';
|
|
6
|
+
export * from './06-ElementRef';
|
|
7
|
+
export * from './07-Views';
|
|
8
|
+
export * from './08-Structurizr';
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { expect, test } from 'vitest';
|
|
2
|
+
import { createTestServices } from '../test';
|
|
3
|
+
const document1 = `
|
|
4
|
+
specification {
|
|
5
|
+
element component
|
|
6
|
+
}
|
|
7
|
+
model {
|
|
8
|
+
component system {
|
|
9
|
+
sub = component {
|
|
10
|
+
component sub1
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
`;
|
|
15
|
+
const document2 = `
|
|
16
|
+
model {
|
|
17
|
+
extend system.sub {
|
|
18
|
+
component sub2 {
|
|
19
|
+
-> sub1
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
`;
|
|
24
|
+
const document3 = `
|
|
25
|
+
model {
|
|
26
|
+
system.sub1 -> system.sub2
|
|
27
|
+
}
|
|
28
|
+
`;
|
|
29
|
+
test('parser smoke: ExtendsElement Scope', async () => {
|
|
30
|
+
const { parse, validateAll } = createTestServices();
|
|
31
|
+
await parse(document1);
|
|
32
|
+
await parse(document2);
|
|
33
|
+
await parse(document3);
|
|
34
|
+
const { errors } = await validateAll();
|
|
35
|
+
expect(errors).toEqual([]);
|
|
36
|
+
});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { toPairs } from 'rambdax';
|
|
2
|
+
import { describe, vi, it } from 'vitest';
|
|
3
|
+
import { createTestServices } from '../test';
|
|
4
|
+
import * as testfiles from './parser-smoke';
|
|
5
|
+
vi.mock('../logger', () => ({
|
|
6
|
+
logger: {
|
|
7
|
+
log: vi.fn(),
|
|
8
|
+
error: vi.fn(),
|
|
9
|
+
warn: vi.fn(),
|
|
10
|
+
info: vi.fn(),
|
|
11
|
+
debug: vi.fn()
|
|
12
|
+
}
|
|
13
|
+
}));
|
|
14
|
+
describe('parser smoke', () => {
|
|
15
|
+
toPairs(testfiles).forEach(([name, document]) => {
|
|
16
|
+
it.concurrent(name, async ({ expect }) => {
|
|
17
|
+
const { validate } = createTestServices();
|
|
18
|
+
const { diagnostics } = await validate(document);
|
|
19
|
+
const errors = diagnostics.map(d => d.message);
|
|
20
|
+
if (name.startsWith('invalid_')) {
|
|
21
|
+
expect(errors).not.toEqual([]);
|
|
22
|
+
}
|
|
23
|
+
else {
|
|
24
|
+
expect(errors).toEqual([]);
|
|
25
|
+
}
|
|
26
|
+
});
|
|
27
|
+
});
|
|
28
|
+
});
|
package/dist/ast.d.ts
CHANGED
package/dist/index.d.ts
CHANGED
package/dist/index.js
CHANGED
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
* This program and the accompanying materials are made available under the
|
|
4
4
|
* terms of the MIT License, which is available in the project root.
|
|
5
5
|
******************************************************************************/
|
|
6
|
+
/// <reference types="react" />
|
|
6
7
|
import { type DocumentSymbolProvider, type MaybePromise } from 'langium';
|
|
7
8
|
import { type DocumentSymbol } from 'vscode-languageserver-protocol';
|
|
8
9
|
import { type LikeC4LangiumDocument, ast } from '../ast';
|
|
@@ -10,7 +10,7 @@ import { toAutoLayout } from '../ast';
|
|
|
10
10
|
import { ElementViewOps, ast, c4hash, cleanParsedModel, isLikeC4LangiumDocument, isParsedLikeC4LangiumDocument, resolveRelationPoints, streamModel, toElementStyle } from '../ast';
|
|
11
11
|
import { elementRef, strictElementRefFqn } from '../elementRef';
|
|
12
12
|
import { logger } from '../logger';
|
|
13
|
-
import { Rpc } from '
|
|
13
|
+
import { Rpc } from '@likec4/language-protocol';
|
|
14
14
|
import { failExpectedNever } from '../utils';
|
|
15
15
|
export class LikeC4ModelBuilder {
|
|
16
16
|
services;
|
|
@@ -259,29 +259,29 @@ export class LikeC4ModelBuilder {
|
|
|
259
259
|
}
|
|
260
260
|
failExpectedNever(astNode);
|
|
261
261
|
}
|
|
262
|
-
parseViewRule(
|
|
263
|
-
if (ast.isViewRuleExpression(
|
|
264
|
-
const exprs =
|
|
262
|
+
parseViewRule(astRule) {
|
|
263
|
+
if (ast.isViewRuleExpression(astRule)) {
|
|
264
|
+
const exprs = astRule.expressions.map(n => this.parseExpression(n));
|
|
265
265
|
return {
|
|
266
|
-
isInclude:
|
|
266
|
+
isInclude: astRule.isInclude,
|
|
267
267
|
exprs
|
|
268
268
|
};
|
|
269
269
|
}
|
|
270
|
-
if (ast.isViewRuleStyle(
|
|
271
|
-
const styleProps = toElementStyle(
|
|
270
|
+
if (ast.isViewRuleStyle(astRule)) {
|
|
271
|
+
const styleProps = toElementStyle(astRule.props);
|
|
272
272
|
return {
|
|
273
|
-
targets:
|
|
273
|
+
targets: astRule.targets.map(n => this.parseElementExpression(n)),
|
|
274
274
|
style: {
|
|
275
275
|
...styleProps
|
|
276
276
|
}
|
|
277
277
|
};
|
|
278
278
|
}
|
|
279
|
-
if (ast.isViewRuleAutoLayout(
|
|
279
|
+
if (ast.isViewRuleAutoLayout(astRule)) {
|
|
280
280
|
return {
|
|
281
|
-
autoLayout: toAutoLayout(
|
|
281
|
+
autoLayout: toAutoLayout(astRule.direction)
|
|
282
282
|
};
|
|
283
283
|
}
|
|
284
|
-
failExpectedNever(
|
|
284
|
+
failExpectedNever(astRule);
|
|
285
285
|
}
|
|
286
286
|
parseElementView(astNode) {
|
|
287
287
|
const viewOfEl = astNode.viewOf && elementRef(astNode.viewOf);
|
|
@@ -327,6 +327,6 @@ export class LikeC4ModelBuilder {
|
|
|
327
327
|
return;
|
|
328
328
|
}
|
|
329
329
|
logger.debug('Send onDidChangeModel');
|
|
330
|
-
await connection.sendNotification(Rpc.onDidChangeModel
|
|
330
|
+
await connection.sendNotification(Rpc.onDidChangeModel);
|
|
331
331
|
}
|
|
332
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 {};
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { expect, test } from 'vitest';
|
|
2
|
+
import { createTestServices } from '../test';
|
|
3
|
+
const { validate } = createTestServices();
|
|
4
|
+
test('elementKindChecks', async () => {
|
|
5
|
+
const { diagnostics } = await validate(`
|
|
6
|
+
specification {
|
|
7
|
+
element component
|
|
8
|
+
element user
|
|
9
|
+
element component
|
|
10
|
+
}
|
|
11
|
+
`);
|
|
12
|
+
expect(diagnostics).toHaveLength(2);
|
|
13
|
+
for (const diagnostic of diagnostics) {
|
|
14
|
+
expect(diagnostic.severity, 'diagnostic severity').toBe(1);
|
|
15
|
+
expect(diagnostic.message, 'diagnostic message').toBe("Duplicate element kind 'component'");
|
|
16
|
+
}
|
|
17
|
+
});
|
|
18
|
+
test('tagChecks', async () => {
|
|
19
|
+
const { diagnostics } = await validate(`
|
|
20
|
+
specification {
|
|
21
|
+
tag tag1
|
|
22
|
+
tag tag2
|
|
23
|
+
tag tag1
|
|
24
|
+
}
|
|
25
|
+
`);
|
|
26
|
+
expect(diagnostics).toHaveLength(2);
|
|
27
|
+
for (const diagnostic of diagnostics) {
|
|
28
|
+
expect(diagnostic.severity, 'diagnostic severity').toBe(1);
|
|
29
|
+
expect(diagnostic.message, 'diagnostic message').toBe("Duplicate tag 'tag1'");
|
|
30
|
+
}
|
|
31
|
+
});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|