@likec4/language-server 0.2.2 → 0.5.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.js +10 -9
- package/dist/builtin.d.ts +4 -0
- package/dist/builtin.js +8 -0
- package/dist/generated/ast.d.ts +12 -3
- package/dist/generated/ast.js +14 -1
- package/dist/generated/grammar.js +142 -14
- package/dist/lsp/DocumentSymbolProvider.js +22 -11
- package/dist/lsp/HoverProvider.js +1 -4
- package/dist/lsp/SemanticTokenProvider.js +14 -12
- 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 +16 -10
- 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 +18 -8
- /package/dist/{lsp → shared}/CodeLensProvider.d.ts +0 -0
package/dist/ast.js
CHANGED
|
@@ -11,7 +11,7 @@ export function c4hash({ c4Specification, c4Elements, c4Relations, c4Views }) {
|
|
|
11
11
|
c4Relations,
|
|
12
12
|
c4Views
|
|
13
13
|
}, {
|
|
14
|
-
respectType: false
|
|
14
|
+
respectType: false
|
|
15
15
|
});
|
|
16
16
|
}
|
|
17
17
|
const idattr = Symbol.for('idattr');
|
|
@@ -39,9 +39,9 @@ export function cleanParsedModel(doc) {
|
|
|
39
39
|
doc.c4Specification = {
|
|
40
40
|
kinds: {}
|
|
41
41
|
};
|
|
42
|
-
const elements = doc.c4Elements = [];
|
|
43
|
-
const relations = doc.c4Relations = [];
|
|
44
|
-
const views = doc.c4Views = [];
|
|
42
|
+
const elements = (doc.c4Elements = []);
|
|
43
|
+
const relations = (doc.c4Relations = []);
|
|
44
|
+
const views = (doc.c4Views = []);
|
|
45
45
|
return {
|
|
46
46
|
elements,
|
|
47
47
|
relations,
|
|
@@ -53,21 +53,22 @@ export function isLikeC4LangiumDocument(doc) {
|
|
|
53
53
|
return doc.textDocument.languageId === LikeC4LanguageMetaData.languageId;
|
|
54
54
|
}
|
|
55
55
|
export function isParsedLikeC4LangiumDocument(doc) {
|
|
56
|
-
return isLikeC4LangiumDocument(doc) &&
|
|
56
|
+
return (isLikeC4LangiumDocument(doc) &&
|
|
57
|
+
['c4Specification', 'c4Elements', 'c4Relations', 'c4Views'].every(key => key in doc));
|
|
57
58
|
}
|
|
58
59
|
export const isValidDocument = (doc) => {
|
|
59
60
|
if (!isLikeC4LangiumDocument(doc))
|
|
60
61
|
return false;
|
|
61
62
|
const { state, parseResult, diagnostics } = doc;
|
|
62
|
-
return (state === DocumentState.Validated
|
|
63
|
-
|
|
64
|
-
|
|
63
|
+
return (state === DocumentState.Validated &&
|
|
64
|
+
parseResult.lexerErrors.length === 0 &&
|
|
65
|
+
(!diagnostics || diagnostics.every(d => d.severity !== 1)));
|
|
65
66
|
};
|
|
66
67
|
export function* streamModel(doc) {
|
|
67
68
|
const elements = doc.parseResult.value.model?.elements ?? [];
|
|
68
69
|
const traverseStack = [...elements];
|
|
69
70
|
let el;
|
|
70
|
-
while (el = traverseStack.shift()) {
|
|
71
|
+
while ((el = traverseStack.shift())) {
|
|
71
72
|
if (ast.isExtendElement(el)) {
|
|
72
73
|
traverseStack.push(...el.body.elements);
|
|
73
74
|
continue;
|
package/dist/builtin.js
ADDED
package/dist/generated/ast.d.ts
CHANGED
|
@@ -16,14 +16,15 @@ export type ElementShape = 'browser' | 'cylinder' | 'person' | 'queue' | 'rectan
|
|
|
16
16
|
export type Expression = ElementExpression | InOutExpression | IncomingExpression | OutgoingExpression | RelationExpression;
|
|
17
17
|
export declare const Expression = "Expression";
|
|
18
18
|
export declare function isExpression(item: unknown): item is Expression;
|
|
19
|
-
export type Name = 'model' | ElementShape | ThemeColor | string;
|
|
19
|
+
export type Name = 'element' | 'model' | ElementShape | ThemeColor | string;
|
|
20
20
|
export type ThemeColor = 'muted' | 'primary' | 'secondary';
|
|
21
21
|
export type View = ElementView;
|
|
22
22
|
export declare const View = "View";
|
|
23
23
|
export declare function isView(item: unknown): item is View;
|
|
24
|
-
export type ViewRule = ViewRuleExpression | ViewRuleStyle;
|
|
24
|
+
export type ViewRule = ViewRuleAutoLayout | ViewRuleExpression | ViewRuleStyle;
|
|
25
25
|
export declare const ViewRule = "ViewRule";
|
|
26
26
|
export declare function isViewRule(item: unknown): item is ViewRule;
|
|
27
|
+
export type ViewRuleLayoutDirection = 'BT' | 'LR' | 'RL' | 'TB';
|
|
27
28
|
export interface ColorProperty extends AstNode {
|
|
28
29
|
readonly $container: ElementStyleProperty | SpecificationElementKindStyle | ViewRuleStyle;
|
|
29
30
|
readonly $type: 'ColorProperty';
|
|
@@ -38,7 +39,7 @@ export interface Element extends AstNode {
|
|
|
38
39
|
body?: ElementBody;
|
|
39
40
|
kind: Reference<ElementKind>;
|
|
40
41
|
name: Name;
|
|
41
|
-
|
|
42
|
+
props: Array<string>;
|
|
42
43
|
}
|
|
43
44
|
export declare const Element = "Element";
|
|
44
45
|
export declare function isElement(item: unknown): item is Element;
|
|
@@ -262,6 +263,13 @@ export interface ViewProperty extends AstNode {
|
|
|
262
263
|
}
|
|
263
264
|
export declare const ViewProperty = "ViewProperty";
|
|
264
265
|
export declare function isViewProperty(item: unknown): item is ViewProperty;
|
|
266
|
+
export interface ViewRuleAutoLayout extends AstNode {
|
|
267
|
+
readonly $container: ElementView;
|
|
268
|
+
readonly $type: 'ViewRuleAutoLayout';
|
|
269
|
+
direction: ViewRuleLayoutDirection;
|
|
270
|
+
}
|
|
271
|
+
export declare const ViewRuleAutoLayout = "ViewRuleAutoLayout";
|
|
272
|
+
export declare function isViewRuleAutoLayout(item: unknown): item is ViewRuleAutoLayout;
|
|
265
273
|
export interface ViewRuleExpression extends AstNode {
|
|
266
274
|
readonly $container: ElementView;
|
|
267
275
|
readonly $type: 'ViewRuleExpression';
|
|
@@ -333,6 +341,7 @@ export interface LikeC4AstType {
|
|
|
333
341
|
View: View;
|
|
334
342
|
ViewProperty: ViewProperty;
|
|
335
343
|
ViewRule: ViewRule;
|
|
344
|
+
ViewRuleAutoLayout: ViewRuleAutoLayout;
|
|
336
345
|
ViewRuleExpression: ViewRuleExpression;
|
|
337
346
|
ViewRuleStyle: ViewRuleStyle;
|
|
338
347
|
WildcardExpression: WildcardExpression;
|
package/dist/generated/ast.js
CHANGED
|
@@ -148,6 +148,10 @@ export const ViewProperty = 'ViewProperty';
|
|
|
148
148
|
export function isViewProperty(item) {
|
|
149
149
|
return reflection.isInstance(item, ViewProperty);
|
|
150
150
|
}
|
|
151
|
+
export const ViewRuleAutoLayout = 'ViewRuleAutoLayout';
|
|
152
|
+
export function isViewRuleAutoLayout(item) {
|
|
153
|
+
return reflection.isInstance(item, ViewRuleAutoLayout);
|
|
154
|
+
}
|
|
151
155
|
export const ViewRuleExpression = 'ViewRuleExpression';
|
|
152
156
|
export function isViewRuleExpression(item) {
|
|
153
157
|
return reflection.isInstance(item, ViewRuleExpression);
|
|
@@ -166,7 +170,7 @@ export function isRelationWithSource(item) {
|
|
|
166
170
|
}
|
|
167
171
|
export class LikeC4AstReflection extends AbstractAstReflection {
|
|
168
172
|
getAllTypes() {
|
|
169
|
-
return ['AStyleProperty', 'ColorProperty', 'Element', 'ElementBody', 'ElementExpression', 'ElementKind', 'ElementProperty', 'ElementRef', 'ElementRefExpression', 'ElementStringProperty', 'ElementStyleProperty', 'ElementView', 'Expression', 'ExtendElement', 'ExtendElementBody', 'InOutExpression', 'IncomingExpression', 'LikeC4Document', 'Model', 'ModelViews', 'OutgoingExpression', 'Relation', 'RelationBody', 'RelationExpression', 'RelationProperty', 'RelationWithSource', 'ShapeProperty', 'SpecificationElementKind', 'SpecificationElementKindStyle', 'SpecificationRule', 'SpecificationTag', 'StrictElementRef', 'Tag', 'Tags', 'View', 'ViewProperty', 'ViewRule', 'ViewRuleExpression', 'ViewRuleStyle', 'WildcardExpression'];
|
|
173
|
+
return ['AStyleProperty', 'ColorProperty', 'Element', 'ElementBody', 'ElementExpression', 'ElementKind', 'ElementProperty', 'ElementRef', 'ElementRefExpression', 'ElementStringProperty', 'ElementStyleProperty', 'ElementView', 'Expression', 'ExtendElement', 'ExtendElementBody', 'InOutExpression', 'IncomingExpression', 'LikeC4Document', 'Model', 'ModelViews', 'OutgoingExpression', 'Relation', 'RelationBody', 'RelationExpression', 'RelationProperty', 'RelationWithSource', 'ShapeProperty', 'SpecificationElementKind', 'SpecificationElementKindStyle', 'SpecificationRule', 'SpecificationTag', 'StrictElementRef', 'Tag', 'Tags', 'View', 'ViewProperty', 'ViewRule', 'ViewRuleAutoLayout', 'ViewRuleExpression', 'ViewRuleStyle', 'WildcardExpression'];
|
|
170
174
|
}
|
|
171
175
|
computeIsSubtype(subtype, supertype) {
|
|
172
176
|
switch (subtype) {
|
|
@@ -195,6 +199,7 @@ export class LikeC4AstReflection extends AbstractAstReflection {
|
|
|
195
199
|
case RelationWithSource: {
|
|
196
200
|
return this.isSubtype(Relation, supertype);
|
|
197
201
|
}
|
|
202
|
+
case ViewRuleAutoLayout:
|
|
198
203
|
case ViewRuleExpression:
|
|
199
204
|
case ViewRuleStyle: {
|
|
200
205
|
return this.isSubtype(ViewRule, supertype);
|
|
@@ -224,6 +229,14 @@ export class LikeC4AstReflection extends AbstractAstReflection {
|
|
|
224
229
|
}
|
|
225
230
|
getTypeMetaData(type) {
|
|
226
231
|
switch (type) {
|
|
232
|
+
case 'Element': {
|
|
233
|
+
return {
|
|
234
|
+
name: 'Element',
|
|
235
|
+
mandatory: [
|
|
236
|
+
{ name: 'props', type: 'array' }
|
|
237
|
+
]
|
|
238
|
+
};
|
|
239
|
+
}
|
|
227
240
|
case 'ElementBody': {
|
|
228
241
|
return {
|
|
229
242
|
name: 'ElementBody',
|
|
@@ -535,6 +535,10 @@ export const LikeC4Grammar = () => loadedLikeC4Grammar ?? (loadedLikeC4Grammar =
|
|
|
535
535
|
},
|
|
536
536
|
"arguments": []
|
|
537
537
|
},
|
|
538
|
+
{
|
|
539
|
+
"$type": "Keyword",
|
|
540
|
+
"value": "element"
|
|
541
|
+
},
|
|
538
542
|
{
|
|
539
543
|
"$type": "Keyword",
|
|
540
544
|
"value": "model"
|
|
@@ -892,23 +896,77 @@ export const LikeC4Grammar = () => loadedLikeC4Grammar ?? (loadedLikeC4Grammar =
|
|
|
892
896
|
},
|
|
893
897
|
"deprecatedSyntax": false
|
|
894
898
|
}
|
|
899
|
+
}
|
|
900
|
+
]
|
|
901
|
+
}
|
|
902
|
+
]
|
|
903
|
+
},
|
|
904
|
+
{
|
|
905
|
+
"$type": "Group",
|
|
906
|
+
"elements": [
|
|
907
|
+
{
|
|
908
|
+
"$type": "Assignment",
|
|
909
|
+
"feature": "props",
|
|
910
|
+
"operator": "+=",
|
|
911
|
+
"terminal": {
|
|
912
|
+
"$type": "RuleCall",
|
|
913
|
+
"rule": {
|
|
914
|
+
"$ref": "#/rules@22"
|
|
895
915
|
},
|
|
916
|
+
"arguments": []
|
|
917
|
+
}
|
|
918
|
+
},
|
|
919
|
+
{
|
|
920
|
+
"$type": "Group",
|
|
921
|
+
"elements": [
|
|
896
922
|
{
|
|
897
923
|
"$type": "Assignment",
|
|
898
|
-
"feature": "
|
|
899
|
-
"operator": "
|
|
924
|
+
"feature": "props",
|
|
925
|
+
"operator": "+=",
|
|
900
926
|
"terminal": {
|
|
901
927
|
"$type": "RuleCall",
|
|
902
928
|
"rule": {
|
|
903
929
|
"$ref": "#/rules@22"
|
|
904
930
|
},
|
|
905
931
|
"arguments": []
|
|
906
|
-
}
|
|
932
|
+
}
|
|
933
|
+
},
|
|
934
|
+
{
|
|
935
|
+
"$type": "Group",
|
|
936
|
+
"elements": [
|
|
937
|
+
{
|
|
938
|
+
"$type": "Assignment",
|
|
939
|
+
"feature": "props",
|
|
940
|
+
"operator": "+=",
|
|
941
|
+
"terminal": {
|
|
942
|
+
"$type": "RuleCall",
|
|
943
|
+
"rule": {
|
|
944
|
+
"$ref": "#/rules@22"
|
|
945
|
+
},
|
|
946
|
+
"arguments": []
|
|
947
|
+
}
|
|
948
|
+
},
|
|
949
|
+
{
|
|
950
|
+
"$type": "Assignment",
|
|
951
|
+
"feature": "props",
|
|
952
|
+
"operator": "+=",
|
|
953
|
+
"terminal": {
|
|
954
|
+
"$type": "RuleCall",
|
|
955
|
+
"rule": {
|
|
956
|
+
"$ref": "#/rules@22"
|
|
957
|
+
},
|
|
958
|
+
"arguments": []
|
|
959
|
+
},
|
|
960
|
+
"cardinality": "?"
|
|
961
|
+
}
|
|
962
|
+
],
|
|
907
963
|
"cardinality": "?"
|
|
908
964
|
}
|
|
909
|
-
]
|
|
965
|
+
],
|
|
966
|
+
"cardinality": "?"
|
|
910
967
|
}
|
|
911
|
-
]
|
|
968
|
+
],
|
|
969
|
+
"cardinality": "?"
|
|
912
970
|
},
|
|
913
971
|
{
|
|
914
972
|
"$type": "Assignment",
|
|
@@ -1864,7 +1922,14 @@ export const LikeC4Grammar = () => loadedLikeC4Grammar ?? (loadedLikeC4Grammar =
|
|
|
1864
1922
|
{
|
|
1865
1923
|
"$type": "RuleCall",
|
|
1866
1924
|
"rule": {
|
|
1867
|
-
"$ref": "#/rules@
|
|
1925
|
+
"$ref": "#/rules@49"
|
|
1926
|
+
},
|
|
1927
|
+
"arguments": []
|
|
1928
|
+
},
|
|
1929
|
+
{
|
|
1930
|
+
"$type": "RuleCall",
|
|
1931
|
+
"rule": {
|
|
1932
|
+
"$ref": "#/rules@48"
|
|
1868
1933
|
},
|
|
1869
1934
|
"arguments": []
|
|
1870
1935
|
}
|
|
@@ -1908,7 +1973,7 @@ export const LikeC4Grammar = () => loadedLikeC4Grammar ?? (loadedLikeC4Grammar =
|
|
|
1908
1973
|
"terminal": {
|
|
1909
1974
|
"$type": "RuleCall",
|
|
1910
1975
|
"rule": {
|
|
1911
|
-
"$ref": "#/rules@
|
|
1976
|
+
"$ref": "#/rules@50"
|
|
1912
1977
|
},
|
|
1913
1978
|
"arguments": []
|
|
1914
1979
|
}
|
|
@@ -1930,7 +1995,7 @@ export const LikeC4Grammar = () => loadedLikeC4Grammar ?? (loadedLikeC4Grammar =
|
|
|
1930
1995
|
"terminal": {
|
|
1931
1996
|
"$type": "RuleCall",
|
|
1932
1997
|
"rule": {
|
|
1933
|
-
"$ref": "#/rules@
|
|
1998
|
+
"$ref": "#/rules@50"
|
|
1934
1999
|
},
|
|
1935
2000
|
"arguments": []
|
|
1936
2001
|
}
|
|
@@ -1947,6 +2012,69 @@ export const LikeC4Grammar = () => loadedLikeC4Grammar ?? (loadedLikeC4Grammar =
|
|
|
1947
2012
|
"parameters": [],
|
|
1948
2013
|
"wildcard": false
|
|
1949
2014
|
},
|
|
2015
|
+
{
|
|
2016
|
+
"$type": "ParserRule",
|
|
2017
|
+
"name": "ViewRuleLayoutDirection",
|
|
2018
|
+
"dataType": "string",
|
|
2019
|
+
"definition": {
|
|
2020
|
+
"$type": "Alternatives",
|
|
2021
|
+
"elements": [
|
|
2022
|
+
{
|
|
2023
|
+
"$type": "Keyword",
|
|
2024
|
+
"value": "TB"
|
|
2025
|
+
},
|
|
2026
|
+
{
|
|
2027
|
+
"$type": "Keyword",
|
|
2028
|
+
"value": "LR"
|
|
2029
|
+
},
|
|
2030
|
+
{
|
|
2031
|
+
"$type": "Keyword",
|
|
2032
|
+
"value": "BT"
|
|
2033
|
+
},
|
|
2034
|
+
{
|
|
2035
|
+
"$type": "Keyword",
|
|
2036
|
+
"value": "RL"
|
|
2037
|
+
}
|
|
2038
|
+
]
|
|
2039
|
+
},
|
|
2040
|
+
"definesHiddenTokens": false,
|
|
2041
|
+
"entry": false,
|
|
2042
|
+
"fragment": false,
|
|
2043
|
+
"hiddenTokens": [],
|
|
2044
|
+
"parameters": [],
|
|
2045
|
+
"wildcard": false
|
|
2046
|
+
},
|
|
2047
|
+
{
|
|
2048
|
+
"$type": "ParserRule",
|
|
2049
|
+
"name": "ViewRuleAutoLayout",
|
|
2050
|
+
"definition": {
|
|
2051
|
+
"$type": "Group",
|
|
2052
|
+
"elements": [
|
|
2053
|
+
{
|
|
2054
|
+
"$type": "Keyword",
|
|
2055
|
+
"value": "autoLayout"
|
|
2056
|
+
},
|
|
2057
|
+
{
|
|
2058
|
+
"$type": "Assignment",
|
|
2059
|
+
"feature": "direction",
|
|
2060
|
+
"operator": "=",
|
|
2061
|
+
"terminal": {
|
|
2062
|
+
"$type": "RuleCall",
|
|
2063
|
+
"rule": {
|
|
2064
|
+
"$ref": "#/rules@47"
|
|
2065
|
+
},
|
|
2066
|
+
"arguments": []
|
|
2067
|
+
}
|
|
2068
|
+
}
|
|
2069
|
+
]
|
|
2070
|
+
},
|
|
2071
|
+
"definesHiddenTokens": false,
|
|
2072
|
+
"entry": false,
|
|
2073
|
+
"fragment": false,
|
|
2074
|
+
"hiddenTokens": [],
|
|
2075
|
+
"parameters": [],
|
|
2076
|
+
"wildcard": false
|
|
2077
|
+
},
|
|
1950
2078
|
{
|
|
1951
2079
|
"$type": "ParserRule",
|
|
1952
2080
|
"name": "ViewRuleStyle",
|
|
@@ -1964,7 +2092,7 @@ export const LikeC4Grammar = () => loadedLikeC4Grammar ?? (loadedLikeC4Grammar =
|
|
|
1964
2092
|
"terminal": {
|
|
1965
2093
|
"$type": "RuleCall",
|
|
1966
2094
|
"rule": {
|
|
1967
|
-
"$ref": "#/rules@
|
|
2095
|
+
"$ref": "#/rules@51"
|
|
1968
2096
|
},
|
|
1969
2097
|
"arguments": []
|
|
1970
2098
|
}
|
|
@@ -1986,7 +2114,7 @@ export const LikeC4Grammar = () => loadedLikeC4Grammar ?? (loadedLikeC4Grammar =
|
|
|
1986
2114
|
"terminal": {
|
|
1987
2115
|
"$type": "RuleCall",
|
|
1988
2116
|
"rule": {
|
|
1989
|
-
"$ref": "#/rules@
|
|
2117
|
+
"$ref": "#/rules@51"
|
|
1990
2118
|
},
|
|
1991
2119
|
"arguments": []
|
|
1992
2120
|
}
|
|
@@ -2069,7 +2197,7 @@ export const LikeC4Grammar = () => loadedLikeC4Grammar ?? (loadedLikeC4Grammar =
|
|
|
2069
2197
|
"terminal": {
|
|
2070
2198
|
"$type": "RuleCall",
|
|
2071
2199
|
"rule": {
|
|
2072
|
-
"$ref": "#/rules@
|
|
2200
|
+
"$ref": "#/rules@51"
|
|
2073
2201
|
},
|
|
2074
2202
|
"arguments": []
|
|
2075
2203
|
}
|
|
@@ -2101,7 +2229,7 @@ export const LikeC4Grammar = () => loadedLikeC4Grammar ?? (loadedLikeC4Grammar =
|
|
|
2101
2229
|
{
|
|
2102
2230
|
"$type": "RuleCall",
|
|
2103
2231
|
"rule": {
|
|
2104
|
-
"$ref": "#/rules@
|
|
2232
|
+
"$ref": "#/rules@51"
|
|
2105
2233
|
},
|
|
2106
2234
|
"arguments": []
|
|
2107
2235
|
},
|
|
@@ -2131,7 +2259,7 @@ export const LikeC4Grammar = () => loadedLikeC4Grammar ?? (loadedLikeC4Grammar =
|
|
|
2131
2259
|
"terminal": {
|
|
2132
2260
|
"$type": "RuleCall",
|
|
2133
2261
|
"rule": {
|
|
2134
|
-
"$ref": "#/rules@
|
|
2262
|
+
"$ref": "#/rules@51"
|
|
2135
2263
|
},
|
|
2136
2264
|
"arguments": []
|
|
2137
2265
|
}
|
|
@@ -2200,7 +2328,7 @@ export const LikeC4Grammar = () => loadedLikeC4Grammar ?? (loadedLikeC4Grammar =
|
|
|
2200
2328
|
{
|
|
2201
2329
|
"$type": "RuleCall",
|
|
2202
2330
|
"rule": {
|
|
2203
|
-
"$ref": "#/rules@
|
|
2331
|
+
"$ref": "#/rules@52"
|
|
2204
2332
|
},
|
|
2205
2333
|
"arguments": []
|
|
2206
2334
|
}
|
|
@@ -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;
|
|
@@ -110,15 +116,18 @@ export class LikeC4DocumentSymbolProvider {
|
|
|
110
116
|
return [];
|
|
111
117
|
const name = astElement.name;
|
|
112
118
|
const kind = astElement.kind.$refText;
|
|
113
|
-
|
|
114
|
-
|
|
119
|
+
// TODO: return the title as well
|
|
120
|
+
const detail = kind; // + (astElement.title ? ': ' + astElement.title : '').replaceAll('\n', ' ').trim()
|
|
121
|
+
return [
|
|
122
|
+
{
|
|
115
123
|
kind: SymbolKind.Constructor,
|
|
116
124
|
name: name,
|
|
117
125
|
range: cst.range,
|
|
118
126
|
selectionRange: nameNode.range,
|
|
119
127
|
detail,
|
|
120
128
|
children: astElement.body?.elements.flatMap(this.getElementsSymbol) ?? []
|
|
121
|
-
}
|
|
129
|
+
}
|
|
130
|
+
];
|
|
122
131
|
};
|
|
123
132
|
getModelViewsSymbols = (astViews) => {
|
|
124
133
|
const cst = astViews?.$cstNode;
|
|
@@ -127,12 +136,14 @@ export class LikeC4DocumentSymbolProvider {
|
|
|
127
136
|
const nameNode = findNodeForProperty(cst, 'name');
|
|
128
137
|
if (!nameNode)
|
|
129
138
|
return [];
|
|
130
|
-
return [
|
|
139
|
+
return [
|
|
140
|
+
{
|
|
131
141
|
kind: SymbolKind.Class,
|
|
132
142
|
name: astViews.name,
|
|
133
143
|
range: cst.range,
|
|
134
144
|
selectionRange: nameNode.range,
|
|
135
145
|
children: []
|
|
136
|
-
}
|
|
146
|
+
}
|
|
147
|
+
];
|
|
137
148
|
};
|
|
138
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,13 +7,13 @@ 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
18
|
// acceptor({
|
|
19
19
|
// node,
|
|
@@ -34,7 +34,9 @@ export class LikeC4SemanticTokenProvider extends AbstractSemanticTokenProvider {
|
|
|
34
34
|
});
|
|
35
35
|
return;
|
|
36
36
|
}
|
|
37
|
-
if (ast.isRelationExpression(node) ||
|
|
37
|
+
if (ast.isRelationExpression(node) ||
|
|
38
|
+
ast.isIncomingExpression(node) ||
|
|
39
|
+
ast.isOutgoingExpression(node)) {
|
|
38
40
|
keyword('->');
|
|
39
41
|
return;
|
|
40
42
|
}
|
|
@@ -74,9 +76,7 @@ export class LikeC4SemanticTokenProvider extends AbstractSemanticTokenProvider {
|
|
|
74
76
|
node,
|
|
75
77
|
property: 'name',
|
|
76
78
|
type: SemanticTokenTypes.type,
|
|
77
|
-
modifier: [
|
|
78
|
-
SemanticTokenModifiers.definition,
|
|
79
|
-
]
|
|
79
|
+
modifier: [SemanticTokenModifiers.definition]
|
|
80
80
|
});
|
|
81
81
|
return;
|
|
82
82
|
}
|
|
@@ -126,7 +126,7 @@ export class LikeC4SemanticTokenProvider extends AbstractSemanticTokenProvider {
|
|
|
126
126
|
acceptor({
|
|
127
127
|
node,
|
|
128
128
|
property: 'key',
|
|
129
|
-
type: SemanticTokenTypes.keyword
|
|
129
|
+
type: SemanticTokenTypes.keyword
|
|
130
130
|
});
|
|
131
131
|
acceptor({
|
|
132
132
|
node,
|
|
@@ -139,7 +139,7 @@ export class LikeC4SemanticTokenProvider extends AbstractSemanticTokenProvider {
|
|
|
139
139
|
acceptor({
|
|
140
140
|
node,
|
|
141
141
|
property: 'key',
|
|
142
|
-
type: SemanticTokenTypes.keyword
|
|
142
|
+
type: SemanticTokenTypes.keyword
|
|
143
143
|
});
|
|
144
144
|
if ('value' in node) {
|
|
145
145
|
acceptor({
|
|
@@ -188,6 +188,10 @@ export class LikeC4SemanticTokenProvider extends AbstractSemanticTokenProvider {
|
|
|
188
188
|
// keyword('steps')
|
|
189
189
|
// return
|
|
190
190
|
// }
|
|
191
|
+
if (ast.isViewRuleAutoLayout(node)) {
|
|
192
|
+
keyword('autoLayout');
|
|
193
|
+
return;
|
|
194
|
+
}
|
|
191
195
|
if (ast.isViewRuleStyle(node)) {
|
|
192
196
|
keyword('style');
|
|
193
197
|
return;
|
|
@@ -203,9 +207,7 @@ export class LikeC4SemanticTokenProvider extends AbstractSemanticTokenProvider {
|
|
|
203
207
|
node,
|
|
204
208
|
property: 'name',
|
|
205
209
|
type: SemanticTokenTypes.variable,
|
|
206
|
-
modifier: [
|
|
207
|
-
SemanticTokenModifiers.declaration,
|
|
208
|
-
]
|
|
210
|
+
modifier: [SemanticTokenModifiers.declaration]
|
|
209
211
|
});
|
|
210
212
|
acceptor({
|
|
211
213
|
node,
|
|
@@ -226,7 +228,7 @@ export class LikeC4SemanticTokenProvider extends AbstractSemanticTokenProvider {
|
|
|
226
228
|
acceptor({
|
|
227
229
|
node,
|
|
228
230
|
property: 'name',
|
|
229
|
-
type: SemanticTokenTypes.variable
|
|
231
|
+
type: SemanticTokenTypes.variable
|
|
230
232
|
});
|
|
231
233
|
}
|
|
232
234
|
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
|
}
|
|
@@ -67,7 +67,7 @@ export class LikeC4ModelBuilder {
|
|
|
67
67
|
return {
|
|
68
68
|
...(kind.shape !== DefaultElementShape ? { shape: kind.shape } : {}),
|
|
69
69
|
...(kind.color !== DefaultThemeColor ? { color: kind.color } : {}),
|
|
70
|
-
...
|
|
70
|
+
...omit(['astPath'], el)
|
|
71
71
|
};
|
|
72
72
|
}
|
|
73
73
|
return null;
|
|
@@ -127,7 +127,7 @@ export class LikeC4ModelBuilder {
|
|
|
127
127
|
const styleProps = toElementStyle(style?.props);
|
|
128
128
|
specification.kinds[kind.name] = {
|
|
129
129
|
color: styleProps.color ?? DefaultThemeColor,
|
|
130
|
-
shape: styleProps.shape ?? DefaultElementShape
|
|
130
|
+
shape: styleProps.shape ?? DefaultElementShape
|
|
131
131
|
};
|
|
132
132
|
}
|
|
133
133
|
catch (e) {
|
|
@@ -181,10 +181,11 @@ export class LikeC4ModelBuilder {
|
|
|
181
181
|
const styleProps = astNode.body?.props.find(ast.isElementStyleProperty)?.props;
|
|
182
182
|
const { color, shape } = toElementStyle(styleProps);
|
|
183
183
|
const astPath = this.getAstNodePath(astNode);
|
|
184
|
-
|
|
185
|
-
const
|
|
186
|
-
|
|
187
|
-
|
|
184
|
+
let [title, description, technology] = astNode.props;
|
|
185
|
+
const bodyProps = astNode.body?.props.filter((p) => ast.isElementStringProperty(p)) ?? [];
|
|
186
|
+
title = title ?? bodyProps.find(p => p.key === 'title')?.value;
|
|
187
|
+
description = description ?? bodyProps.find(p => p.key === 'description')?.value;
|
|
188
|
+
technology = technology ?? bodyProps.find(p => p.key === 'technology')?.value;
|
|
188
189
|
return {
|
|
189
190
|
id,
|
|
190
191
|
kind,
|
|
@@ -194,7 +195,7 @@ export class LikeC4ModelBuilder {
|
|
|
194
195
|
...(description && { description }),
|
|
195
196
|
...(tags.length > 0 ? { tags } : {}),
|
|
196
197
|
...(shape && shape !== DefaultElementShape ? { shape } : {}),
|
|
197
|
-
...(color && color !== DefaultThemeColor ? { color } : {})
|
|
198
|
+
...(color && color !== DefaultThemeColor ? { color } : {})
|
|
198
199
|
};
|
|
199
200
|
}
|
|
200
201
|
parseRelation(astNode) {
|
|
@@ -207,11 +208,11 @@ export class LikeC4ModelBuilder {
|
|
|
207
208
|
target
|
|
208
209
|
};
|
|
209
210
|
const id = objectHash(hashdata);
|
|
210
|
-
const title = astNode.definition?.props.find(p => p.key === 'title')?.value ?? '';
|
|
211
|
+
const title = astNode.title ?? astNode.definition?.props.find(p => p.key === 'title')?.value ?? '';
|
|
211
212
|
return {
|
|
212
213
|
id,
|
|
213
214
|
...hashdata,
|
|
214
|
-
title
|
|
215
|
+
title
|
|
215
216
|
};
|
|
216
217
|
}
|
|
217
218
|
parseElementExpression(astNode) {
|
|
@@ -252,7 +253,7 @@ export class LikeC4ModelBuilder {
|
|
|
252
253
|
if (ast.isRelationExpression(astNode)) {
|
|
253
254
|
return {
|
|
254
255
|
source: this.parseElementExpression(astNode.source),
|
|
255
|
-
target: this.parseElementExpression(astNode.target)
|
|
256
|
+
target: this.parseElementExpression(astNode.target)
|
|
256
257
|
};
|
|
257
258
|
}
|
|
258
259
|
failExpectedNever(astNode);
|
|
@@ -274,6 +275,11 @@ export class LikeC4ModelBuilder {
|
|
|
274
275
|
}
|
|
275
276
|
};
|
|
276
277
|
}
|
|
278
|
+
if (ast.isViewRuleAutoLayout(astNode)) {
|
|
279
|
+
return {
|
|
280
|
+
autoLayout: astNode.direction
|
|
281
|
+
};
|
|
282
|
+
}
|
|
277
283
|
failExpectedNever(astNode);
|
|
278
284
|
}
|
|
279
285
|
parseElementView(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
|
}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import { resolveRelationPoints } from '../ast';
|
|
2
|
+
import { isSameHierarchy } from '@likec4/core/utils';
|
|
3
|
+
export const relationChecks = (services) => {
|
|
4
|
+
const fqnIndex = services.likec4.FqnIndex;
|
|
5
|
+
return (el, accept) => {
|
|
6
|
+
try {
|
|
7
|
+
const coupling = resolveRelationPoints(el);
|
|
8
|
+
const target = fqnIndex.get(coupling.target);
|
|
9
|
+
if (!target) {
|
|
10
|
+
return accept('error', 'Invalid target', {
|
|
11
|
+
node: el,
|
|
12
|
+
property: 'target'
|
|
13
|
+
});
|
|
14
|
+
}
|
|
15
|
+
const source = fqnIndex.get(coupling.source);
|
|
16
|
+
if (!source) {
|
|
17
|
+
return accept('error', 'Invalid source', {
|
|
18
|
+
node: el
|
|
19
|
+
});
|
|
20
|
+
}
|
|
21
|
+
if (isSameHierarchy(source, target)) {
|
|
22
|
+
return accept('error', 'Invalid relation (same hierarchy)', {
|
|
23
|
+
node: el
|
|
24
|
+
});
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
catch (e) {
|
|
28
|
+
if (e instanceof Error) {
|
|
29
|
+
return accept('error', e.message, {
|
|
30
|
+
node: el
|
|
31
|
+
});
|
|
32
|
+
}
|
|
33
|
+
accept('error', 'Invalid relation', {
|
|
34
|
+
node: el
|
|
35
|
+
});
|
|
36
|
+
}
|
|
37
|
+
// const fqn = fqnIndex.get(el)
|
|
38
|
+
// if (!fqn) {
|
|
39
|
+
// accept('error', 'Not indexed', {
|
|
40
|
+
// node: el,
|
|
41
|
+
// property: 'name',
|
|
42
|
+
// })
|
|
43
|
+
// return
|
|
44
|
+
// }
|
|
45
|
+
// const withSameFqn = fqnIndex.byFqn(fqn)
|
|
46
|
+
// if (withSameFqn.length > 1) {
|
|
47
|
+
// accept('error', `Duplicate element name ${el.name !== fqn ? el.name +' (' + fqn + ')' : el.name}`, {
|
|
48
|
+
// node: el,
|
|
49
|
+
// property: 'name',
|
|
50
|
+
// })
|
|
51
|
+
// }
|
|
52
|
+
};
|
|
53
|
+
};
|
|
@@ -2,14 +2,15 @@ import { ast } from '../ast';
|
|
|
2
2
|
export const elementKindChecks = (services) => {
|
|
3
3
|
const index = services.shared.workspace.IndexManager;
|
|
4
4
|
return (node, accept) => {
|
|
5
|
-
const sameKinds = index
|
|
5
|
+
const sameKinds = index
|
|
6
|
+
.allElements(ast.ElementKind)
|
|
6
7
|
.filter(n => n.name === node.name)
|
|
7
8
|
.limit(2)
|
|
8
9
|
.count();
|
|
9
10
|
if (sameKinds > 1) {
|
|
10
11
|
accept('error', `Duplicate element kind '${node.name}'`, {
|
|
11
12
|
node: node,
|
|
12
|
-
property: 'name'
|
|
13
|
+
property: 'name'
|
|
13
14
|
});
|
|
14
15
|
}
|
|
15
16
|
};
|
|
@@ -17,14 +18,15 @@ export const elementKindChecks = (services) => {
|
|
|
17
18
|
export const tagChecks = (services) => {
|
|
18
19
|
const index = services.shared.workspace.IndexManager;
|
|
19
20
|
return (node, accept) => {
|
|
20
|
-
const sameKinds = index
|
|
21
|
+
const sameKinds = index
|
|
22
|
+
.allElements(ast.Tag)
|
|
21
23
|
.filter(n => n.name === node.name)
|
|
22
24
|
.limit(2)
|
|
23
25
|
.count();
|
|
24
26
|
if (sameKinds > 1) {
|
|
25
27
|
accept('error', `Duplicate tag '${node.name}'`, {
|
|
26
28
|
node: node,
|
|
27
|
-
property: 'name'
|
|
29
|
+
property: 'name'
|
|
28
30
|
});
|
|
29
31
|
}
|
|
30
32
|
};
|
package/dist/validation/view.js
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@likec4/language-server",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.5.0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"bugs": "https://github.com/likec4/likec4/issues",
|
|
6
6
|
"homepage": "https://like-c4.dev",
|
|
@@ -24,6 +24,11 @@
|
|
|
24
24
|
"types": "./dist/protocol.d.ts",
|
|
25
25
|
"import": "./dist/protocol.js",
|
|
26
26
|
"require": "./dist/protocol.cjs"
|
|
27
|
+
},
|
|
28
|
+
"./builtin": {
|
|
29
|
+
"types": "./dist/builtin.d.ts",
|
|
30
|
+
"import": "./dist/builtin.js",
|
|
31
|
+
"require": "./dist/builtin.cjs"
|
|
27
32
|
}
|
|
28
33
|
},
|
|
29
34
|
"publishConfig": {
|
|
@@ -41,6 +46,11 @@
|
|
|
41
46
|
"types": "./dist/protocol.d.ts",
|
|
42
47
|
"import": "./dist/protocol.js",
|
|
43
48
|
"require": "./dist/protocol.cjs"
|
|
49
|
+
},
|
|
50
|
+
"./builtin": {
|
|
51
|
+
"types": "./dist/builtin.d.ts",
|
|
52
|
+
"import": "./dist/builtin.js",
|
|
53
|
+
"require": "./dist/builtin.cjs"
|
|
44
54
|
}
|
|
45
55
|
}
|
|
46
56
|
},
|
|
@@ -53,14 +63,14 @@
|
|
|
53
63
|
"watch:ts": "tsc --watch",
|
|
54
64
|
"generate": "langium generate",
|
|
55
65
|
"build": "run-s 'build:langium' 'build:ts'",
|
|
56
|
-
"dev": "run-p 'watch:*'",
|
|
66
|
+
"dev": "run generate && run-p 'watch:*'",
|
|
57
67
|
"lint": "run -T eslint src/ --fix",
|
|
58
|
-
"clean": "rimraf dist",
|
|
68
|
+
"clean": "run -T rimraf dist contrib",
|
|
59
69
|
"test": "vitest run",
|
|
60
70
|
"test:watch": "vitest"
|
|
61
71
|
},
|
|
62
72
|
"dependencies": {
|
|
63
|
-
"@likec4/core": "0.
|
|
73
|
+
"@likec4/core": "0.5.0",
|
|
64
74
|
"@mobily/ts-belt": "^3.13.1",
|
|
65
75
|
"langium": "^1.1.0",
|
|
66
76
|
"nanoid": "^4.0.2",
|
|
@@ -68,17 +78,17 @@
|
|
|
68
78
|
"rambdax": "^9.1.0",
|
|
69
79
|
"strip-indent": "^4.0.0",
|
|
70
80
|
"tiny-invariant": "^1.3.1",
|
|
71
|
-
"type-fest": "^3.
|
|
81
|
+
"type-fest": "^3.8.0",
|
|
72
82
|
"vscode-languageserver-protocol": "3.17.2",
|
|
73
83
|
"vscode-uri": "3.0.7"
|
|
74
84
|
},
|
|
75
85
|
"devDependencies": {
|
|
76
|
-
"@types/node": "^18.15.
|
|
86
|
+
"@types/node": "^18.15.11",
|
|
77
87
|
"@types/object-hash": "^3.0.2",
|
|
78
88
|
"langium-cli": "^1.1.0",
|
|
79
89
|
"npm-run-all": "^4.1.5",
|
|
80
|
-
"typescript": "^5.0.
|
|
90
|
+
"typescript": "^5.0.4",
|
|
81
91
|
"vite": "^4.2.1",
|
|
82
|
-
"vitest": "^0.
|
|
92
|
+
"vitest": "^0.30.1"
|
|
83
93
|
}
|
|
84
94
|
}
|
|
File without changes
|