@likec4/language-server 1.2.2 → 1.4.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/package.json +19 -8
- package/src/ast.ts +2 -0
- package/src/generated/ast.ts +157 -123
- package/src/generated/grammar.ts +2 -2
- package/src/generated/module.ts +1 -1
- package/src/like-c4.langium +53 -34
- package/src/logger.ts +21 -7
- package/src/lsp/CompletionProvider.ts +7 -0
- package/src/lsp/SemanticTokenProvider.ts +78 -17
- package/src/lsp/index.ts +1 -0
- package/src/model/model-builder.ts +3 -39
- package/src/model/model-parser.ts +19 -4
- package/src/model-change/ModelChanges.ts +58 -53
- package/src/model-change/changeElementStyle.ts +5 -6
- package/src/model-change/saveManualLayout.ts +43 -0
- package/src/model-graph/LikeC4ModelGraph.ts +304 -0
- package/src/model-graph/compute-view/__test__/fixture.ts +438 -0
- package/src/model-graph/compute-view/compute.ts +430 -0
- package/src/model-graph/compute-view/index.ts +33 -0
- package/src/model-graph/compute-view/predicates.ts +404 -0
- package/src/model-graph/dynamic-view/__test__/fixture.ts +56 -0
- package/src/model-graph/dynamic-view/compute.ts +198 -0
- package/src/model-graph/dynamic-view/index.ts +29 -0
- package/src/model-graph/index.ts +3 -0
- package/src/model-graph/utils/applyElementCustomProperties.ts +49 -0
- package/src/model-graph/utils/applyViewRuleStyles.ts +68 -0
- package/src/model-graph/utils/buildComputeNodes.ts +61 -0
- package/src/model-graph/utils/sortNodes.ts +105 -0
- package/src/module.ts +3 -0
- package/src/protocol.ts +3 -18
- package/src/references/scope-computation.ts +29 -11
- package/src/references/scope-provider.ts +22 -16
- package/src/validation/view.ts +9 -4
- package/src/view-utils/manual-layout.ts +93 -0
- package/contrib/likec4.monarch.ts +0 -41
- package/src/lsp/DocumentLinkProvider.test.ts +0 -66
package/src/like-c4.langium
CHANGED
|
@@ -21,7 +21,11 @@ RelationshipKind:
|
|
|
21
21
|
|
|
22
22
|
SpecificationRule:
|
|
23
23
|
name='specification' '{'
|
|
24
|
-
(
|
|
24
|
+
(
|
|
25
|
+
elements+=SpecificationElementKind |
|
|
26
|
+
tags+=SpecificationTag |
|
|
27
|
+
relationships+=SpecificationRelationshipKind
|
|
28
|
+
)*
|
|
25
29
|
'}';
|
|
26
30
|
|
|
27
31
|
SpecificationElementKind:
|
|
@@ -47,7 +51,8 @@ Model:
|
|
|
47
51
|
ExplicitRelation |
|
|
48
52
|
Element
|
|
49
53
|
)*
|
|
50
|
-
'}'
|
|
54
|
+
'}'
|
|
55
|
+
;
|
|
51
56
|
|
|
52
57
|
Element:
|
|
53
58
|
(
|
|
@@ -61,16 +66,17 @@ Element:
|
|
|
61
66
|
)?
|
|
62
67
|
)?
|
|
63
68
|
)?
|
|
64
|
-
|
|
69
|
+
body=ElementBody?
|
|
65
70
|
;
|
|
66
71
|
|
|
67
|
-
ElementBody:
|
|
72
|
+
ElementBody: '{'
|
|
68
73
|
tags=Tags?
|
|
69
74
|
props+=ElementProperty*
|
|
70
75
|
elements+=(
|
|
71
76
|
Relation |
|
|
72
77
|
Element
|
|
73
78
|
)*
|
|
79
|
+
'}'
|
|
74
80
|
;
|
|
75
81
|
|
|
76
82
|
ElementProperty:
|
|
@@ -80,37 +86,37 @@ ElementStringProperty:
|
|
|
80
86
|
key=('title' | 'technology' | 'description') Colon? value=String SemiColon?;
|
|
81
87
|
|
|
82
88
|
ExtendElement:
|
|
83
|
-
'extend' element=FqnElementRef
|
|
84
|
-
body=ExtendElementBody
|
|
85
|
-
'}'
|
|
89
|
+
'extend' element=FqnElementRef body=ExtendElementBody
|
|
86
90
|
;
|
|
87
91
|
|
|
88
|
-
ExtendElementBody:
|
|
92
|
+
ExtendElementBody: '{'
|
|
89
93
|
elements+=(
|
|
90
94
|
ExplicitRelation |
|
|
91
95
|
Element
|
|
92
96
|
)*
|
|
97
|
+
'}'
|
|
93
98
|
;
|
|
94
99
|
|
|
95
100
|
//
|
|
96
101
|
FqnElementRef:
|
|
97
|
-
el=[Element] ({infer FqnElementRef.parent=current}
|
|
102
|
+
el=[Element] ({infer FqnElementRef.parent=current} dot=StickyDot el=[Element])*;
|
|
98
103
|
|
|
99
104
|
ElementRef:
|
|
100
|
-
el=[Element] ({infer ElementRef.parent=current}
|
|
105
|
+
el=[Element] ({infer ElementRef.parent=current} dot=StickyDot el=[Element])*;
|
|
101
106
|
|
|
102
107
|
Tags:
|
|
103
|
-
value+=[Tag:TagId]
|
|
108
|
+
(value+=[Tag:TagId] comma+=(Comma | SemiColon)?)+
|
|
109
|
+
;
|
|
104
110
|
|
|
105
111
|
Relation:
|
|
106
112
|
ExplicitRelation | ImplicitRelation;
|
|
107
113
|
|
|
108
114
|
fragment RelationFragment:
|
|
109
|
-
('->' | '-[' kind=[RelationshipKind] ']->')
|
|
115
|
+
('->' | '-[' kind=[RelationshipKind] ']->' | kind=[RelationshipKind:DotId] )
|
|
110
116
|
target=ElementRef
|
|
111
117
|
title=String?
|
|
112
118
|
tags=Tags?
|
|
113
|
-
|
|
119
|
+
body=RelationBody?
|
|
114
120
|
;
|
|
115
121
|
|
|
116
122
|
ExplicitRelation:
|
|
@@ -119,9 +125,10 @@ ExplicitRelation:
|
|
|
119
125
|
ImplicitRelation:
|
|
120
126
|
('this' | 'it')? RelationFragment;
|
|
121
127
|
|
|
122
|
-
RelationBody:
|
|
128
|
+
RelationBody: '{'
|
|
123
129
|
tags=Tags?
|
|
124
130
|
props+=RelationProperty*
|
|
131
|
+
'}'
|
|
125
132
|
;
|
|
126
133
|
|
|
127
134
|
RelationProperty:
|
|
@@ -142,8 +149,8 @@ RelationStyleProperty:
|
|
|
142
149
|
ModelViews:
|
|
143
150
|
name='views' '{'
|
|
144
151
|
views+=(
|
|
145
|
-
|
|
146
|
-
|
|
152
|
+
DynamicView |
|
|
153
|
+
ElementView
|
|
147
154
|
)*
|
|
148
155
|
'}';
|
|
149
156
|
|
|
@@ -154,19 +161,18 @@ ElementView:
|
|
|
154
161
|
'extends' extends=ElementViewRef |
|
|
155
162
|
'of' viewOf=ElementRef
|
|
156
163
|
)?
|
|
157
|
-
|
|
164
|
+
body=ElementViewBody
|
|
158
165
|
;
|
|
159
166
|
|
|
160
167
|
DynamicView:
|
|
161
|
-
'dynamic' 'view' name=Id
|
|
162
|
-
body=DynamicViewBody
|
|
163
|
-
'}'
|
|
168
|
+
'dynamic' 'view' name=Id body=DynamicViewBody
|
|
164
169
|
;
|
|
165
170
|
|
|
166
|
-
DynamicViewBody:
|
|
171
|
+
DynamicViewBody: '{'
|
|
167
172
|
tags=Tags?
|
|
168
173
|
props+=ViewProperty*
|
|
169
174
|
(steps+=DynamicViewStep | rules+=DynamicViewRule)*
|
|
175
|
+
'}'
|
|
170
176
|
;
|
|
171
177
|
|
|
172
178
|
ViewRef:
|
|
@@ -175,12 +181,15 @@ ViewRef:
|
|
|
175
181
|
ElementViewRef:
|
|
176
182
|
view=[ElementView];
|
|
177
183
|
|
|
178
|
-
ElementViewBody:
|
|
184
|
+
ElementViewBody: '{'
|
|
179
185
|
tags=Tags?
|
|
180
186
|
props+=ViewProperty*
|
|
181
187
|
rules+=ViewRule*
|
|
188
|
+
'}'
|
|
182
189
|
;
|
|
183
190
|
|
|
191
|
+
type StringProperty = ElementStringProperty| ViewStringProperty;
|
|
192
|
+
|
|
184
193
|
ViewProperty:
|
|
185
194
|
ViewStringProperty | LinkProperty
|
|
186
195
|
;
|
|
@@ -209,15 +218,15 @@ DynamicViewStep:
|
|
|
209
218
|
|
|
210
219
|
ViewRulePredicate:
|
|
211
220
|
({infer IncludePredicate} 'include' | {infer ExcludePredicate} 'exclude')
|
|
212
|
-
expressions+=ViewRulePredicateExpr (Comma expressions+=ViewRulePredicateExpr)* Comma?
|
|
221
|
+
expressions+=ViewRulePredicateExpr (commas+=Comma expressions+=ViewRulePredicateExpr)* Comma?
|
|
213
222
|
;
|
|
214
223
|
|
|
215
224
|
DynamicViewRulePredicate:
|
|
216
|
-
'include' expressions+=ViewRulePredicateExpr (Comma expressions+=ViewRulePredicateExpr)* Comma?
|
|
225
|
+
'include' expressions+=ViewRulePredicateExpr (commas+=Comma expressions+=ViewRulePredicateExpr)* Comma?
|
|
217
226
|
;
|
|
218
227
|
|
|
219
228
|
ViewRuleStyle:
|
|
220
|
-
'style' targets+=ElementExpr (Comma targets+=ElementExpr)* Comma? '{'
|
|
229
|
+
'style' targets+=ElementExpr (commas+=Comma targets+=ElementExpr)* Comma? '{'
|
|
221
230
|
styleprops+=StyleProperty*
|
|
222
231
|
'}';
|
|
223
232
|
|
|
@@ -227,7 +236,7 @@ ViewRuleAutoLayout:
|
|
|
227
236
|
ViewRulePredicateExpr:
|
|
228
237
|
InOutExpr |
|
|
229
238
|
ElementExpr (
|
|
230
|
-
{infer CustomElementExpr.target=current} 'with'
|
|
239
|
+
{infer CustomElementExpr.target=current} 'with' body=CustomElementExprBody |
|
|
231
240
|
{infer RelationExpr.source=current} (isBidirectional?='<->' | '->') target=ElementExpr |
|
|
232
241
|
{infer OutgoingExpr.from=current} '->'
|
|
233
242
|
)?
|
|
@@ -251,7 +260,7 @@ WildcardExpr:
|
|
|
251
260
|
;
|
|
252
261
|
|
|
253
262
|
ElementSelectorExpr infers ElementExpr:
|
|
254
|
-
'element'
|
|
263
|
+
'element' StickyDot (
|
|
255
264
|
{infer ElementTagExpr} 'tag' IsEqual tag=[Tag:TagId] |
|
|
256
265
|
{infer ElementKindExpr} 'kind' IsEqual kind=[ElementKind]
|
|
257
266
|
)
|
|
@@ -264,16 +273,17 @@ DescedantsExpr infers ElementExpr:
|
|
|
264
273
|
)?
|
|
265
274
|
;
|
|
266
275
|
|
|
267
|
-
CustomElementExprBody:
|
|
276
|
+
CustomElementExprBody: '{'
|
|
268
277
|
props+=(
|
|
269
278
|
NavigateToProperty |
|
|
270
279
|
ElementStringProperty |
|
|
271
280
|
StyleProperty
|
|
272
281
|
)*
|
|
282
|
+
'}'
|
|
273
283
|
;
|
|
274
284
|
|
|
275
285
|
NavigateToProperty:
|
|
276
|
-
'navigateTo' value=ViewRef;
|
|
286
|
+
key='navigateTo' value=ViewRef;
|
|
277
287
|
|
|
278
288
|
// Common properties -------------------------------------
|
|
279
289
|
|
|
@@ -323,7 +333,11 @@ RelationshipStyleProperty:
|
|
|
323
333
|
ColorProperty | LineProperty | ArrowProperty;
|
|
324
334
|
|
|
325
335
|
LineOptions returns string:
|
|
326
|
-
'solid' |
|
|
336
|
+
'solid' |
|
|
337
|
+
'dashed' |
|
|
338
|
+
'dotted'
|
|
339
|
+
;
|
|
340
|
+
|
|
327
341
|
ArrowType returns string:
|
|
328
342
|
'none' |
|
|
329
343
|
'normal' |
|
|
@@ -345,7 +359,10 @@ Uri returns string:
|
|
|
345
359
|
// Percent returns string: PERCENT;
|
|
346
360
|
|
|
347
361
|
TagId returns string:
|
|
348
|
-
|
|
362
|
+
Hash Id;
|
|
363
|
+
|
|
364
|
+
DotId returns string:
|
|
365
|
+
Dot Id;
|
|
349
366
|
|
|
350
367
|
Id returns string:
|
|
351
368
|
IdTerminal | ElementShape | ThemeColor | ArrowType | LineOptions | 'element' | 'model';
|
|
@@ -378,15 +395,17 @@ terminal URI_RELATIVE: /\.{0,2}\/[^\/]\S+/;
|
|
|
378
395
|
|
|
379
396
|
terminal DotUnderscore: /\b\._/;
|
|
380
397
|
terminal DotWildcard: /\b\.\*/;
|
|
381
|
-
terminal
|
|
382
|
-
|
|
398
|
+
terminal Hash: '#';
|
|
399
|
+
|
|
400
|
+
// No space allowed before dot
|
|
401
|
+
terminal StickyDot: /\b\./;
|
|
402
|
+
terminal Dot: '.';
|
|
383
403
|
terminal NotEqual: /\!\={1,2}/;
|
|
384
404
|
terminal Eq: /\={1,2}/;
|
|
385
405
|
terminal Colon: ':';
|
|
386
406
|
terminal SemiColon: ';';
|
|
387
407
|
terminal Comma: ',';
|
|
388
408
|
terminal Percent: /\b\d+%/;
|
|
389
|
-
// terminal Percent: ('0'..'9')+ '%';
|
|
390
409
|
|
|
391
410
|
terminal String: /"[^"]*"|'[^']*'/;
|
|
392
411
|
|
package/src/logger.ts
CHANGED
|
@@ -17,17 +17,23 @@ export const logger = {
|
|
|
17
17
|
if (isSilent) return
|
|
18
18
|
console.info(message)
|
|
19
19
|
},
|
|
20
|
-
warn(message:
|
|
20
|
+
warn(message: unknown) {
|
|
21
21
|
if (isSilent) return
|
|
22
|
-
|
|
22
|
+
if (typeof message === 'string' || message instanceof Error) {
|
|
23
|
+
console.warn(message)
|
|
24
|
+
return
|
|
25
|
+
}
|
|
26
|
+
const error = normalizeError(message)
|
|
27
|
+
console.warn(`${error.name}: ${error.message}`)
|
|
23
28
|
},
|
|
24
|
-
error(message:
|
|
29
|
+
error(message: unknown) {
|
|
25
30
|
if (isSilent) return
|
|
26
|
-
if (typeof message === 'string') {
|
|
31
|
+
if (typeof message === 'string' || message instanceof Error) {
|
|
27
32
|
console.error(message)
|
|
28
33
|
return
|
|
29
34
|
}
|
|
30
|
-
|
|
35
|
+
const error = normalizeError(message)
|
|
36
|
+
console.error(`${error.name}: ${error.message}`, error)
|
|
31
37
|
},
|
|
32
38
|
silent(silent = true) {
|
|
33
39
|
isSilent = silent
|
|
@@ -36,8 +42,16 @@ export const logger = {
|
|
|
36
42
|
|
|
37
43
|
export type Logger = typeof logger
|
|
38
44
|
|
|
39
|
-
export function logError(
|
|
40
|
-
|
|
45
|
+
export function logError(err: unknown): void {
|
|
46
|
+
if (typeof err === 'string') {
|
|
47
|
+
logger.error(err)
|
|
48
|
+
return
|
|
49
|
+
}
|
|
50
|
+
if (err instanceof Error) {
|
|
51
|
+
logger.error(err.stack ?? err.message)
|
|
52
|
+
return
|
|
53
|
+
}
|
|
54
|
+
logger.error(normalizeError(err))
|
|
41
55
|
}
|
|
42
56
|
|
|
43
57
|
export function logWarnError(err: unknown): void {
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { type CompletionProviderOptions, DefaultCompletionProvider } from 'langium/lsp'
|
|
2
|
+
|
|
3
|
+
export class LikeC4CompletionProvider extends DefaultCompletionProvider {
|
|
4
|
+
readonly completionOptions = {
|
|
5
|
+
triggerCharacters: ['.']
|
|
6
|
+
} satisfies CompletionProviderOptions
|
|
7
|
+
}
|
|
@@ -9,17 +9,22 @@ export class LikeC4SemanticTokenProvider extends AbstractSemanticTokenProvider {
|
|
|
9
9
|
node: AstNode,
|
|
10
10
|
acceptor: SemanticTokenAcceptor
|
|
11
11
|
): void | undefined | 'prune' {
|
|
12
|
+
if (ast.isRelationshipKind(node)) {
|
|
13
|
+
return acceptor({
|
|
14
|
+
node,
|
|
15
|
+
property: 'name',
|
|
16
|
+
type: SemanticTokenTypes.function
|
|
17
|
+
})
|
|
18
|
+
}
|
|
12
19
|
if (ast.isRelation(node) && 'kind' in node) {
|
|
13
|
-
acceptor({
|
|
20
|
+
return acceptor({
|
|
14
21
|
node,
|
|
15
22
|
property: 'kind',
|
|
16
|
-
type: SemanticTokenTypes.
|
|
17
|
-
modifier: [SemanticTokenModifiers.definition]
|
|
23
|
+
type: SemanticTokenTypes.function
|
|
18
24
|
})
|
|
19
25
|
}
|
|
20
|
-
|
|
21
26
|
if (ast.isElementViewRef(node)) {
|
|
22
|
-
acceptor({
|
|
27
|
+
return acceptor({
|
|
23
28
|
node,
|
|
24
29
|
property: 'view',
|
|
25
30
|
type: SemanticTokenTypes.variable
|
|
@@ -28,15 +33,24 @@ export class LikeC4SemanticTokenProvider extends AbstractSemanticTokenProvider {
|
|
|
28
33
|
if (ast.isDescedantsExpr(node) && node.$cstNode) {
|
|
29
34
|
acceptor({
|
|
30
35
|
cst: node.$cstNode,
|
|
31
|
-
type: SemanticTokenTypes.variable
|
|
36
|
+
type: SemanticTokenTypes.variable,
|
|
37
|
+
modifier: [
|
|
38
|
+
SemanticTokenModifiers.definition,
|
|
39
|
+
SemanticTokenModifiers.readonly
|
|
40
|
+
]
|
|
32
41
|
})
|
|
33
42
|
return 'prune'
|
|
34
43
|
}
|
|
35
44
|
if (ast.isWildcardExpr(node) && node.$cstNode) {
|
|
36
45
|
acceptor({
|
|
37
46
|
cst: node.$cstNode,
|
|
38
|
-
type: SemanticTokenTypes.variable
|
|
47
|
+
type: SemanticTokenTypes.variable,
|
|
48
|
+
modifier: [
|
|
49
|
+
SemanticTokenModifiers.definition,
|
|
50
|
+
SemanticTokenModifiers.readonly
|
|
51
|
+
]
|
|
39
52
|
})
|
|
53
|
+
return 'prune'
|
|
40
54
|
}
|
|
41
55
|
|
|
42
56
|
if (ast.isElementKindExpr(node)) {
|
|
@@ -59,33 +73,50 @@ export class LikeC4SemanticTokenProvider extends AbstractSemanticTokenProvider {
|
|
|
59
73
|
acceptor({
|
|
60
74
|
node,
|
|
61
75
|
property: 'el',
|
|
62
|
-
type: node.parent ? SemanticTokenTypes.property : SemanticTokenTypes.variable
|
|
76
|
+
type: node.parent ? SemanticTokenTypes.property : SemanticTokenTypes.variable,
|
|
77
|
+
modifier: [
|
|
78
|
+
SemanticTokenModifiers.definition,
|
|
79
|
+
SemanticTokenModifiers.readonly
|
|
80
|
+
]
|
|
63
81
|
})
|
|
82
|
+
return !node.parent ? 'prune' : undefined
|
|
64
83
|
}
|
|
65
84
|
if (ast.isSpecificationElementKind(node) || ast.isSpecificationRelationshipKind(node)) {
|
|
66
85
|
acceptor({
|
|
67
86
|
node,
|
|
68
87
|
property: 'kind',
|
|
69
88
|
type: SemanticTokenTypes.type,
|
|
70
|
-
modifier: [
|
|
89
|
+
modifier: [
|
|
90
|
+
SemanticTokenModifiers.declaration,
|
|
91
|
+
SemanticTokenModifiers.readonly
|
|
92
|
+
]
|
|
71
93
|
})
|
|
72
94
|
}
|
|
73
95
|
if (ast.isTags(node)) {
|
|
74
96
|
acceptor({
|
|
75
97
|
node,
|
|
76
98
|
property: 'value',
|
|
77
|
-
type: SemanticTokenTypes.
|
|
78
|
-
modifier: [SemanticTokenModifiers.definition]
|
|
99
|
+
type: SemanticTokenTypes.interface
|
|
79
100
|
})
|
|
80
101
|
}
|
|
81
102
|
if (ast.isTag(node)) {
|
|
82
|
-
acceptor({
|
|
103
|
+
return acceptor({
|
|
83
104
|
node,
|
|
84
105
|
property: 'name',
|
|
85
106
|
type: SemanticTokenTypes.type,
|
|
86
107
|
modifier: [SemanticTokenModifiers.definition]
|
|
87
108
|
})
|
|
88
109
|
}
|
|
110
|
+
if (
|
|
111
|
+
ast.isRelationStyleProperty(node)
|
|
112
|
+
|| (ast.isStyleProperties(node) && ast.isElementBody(node.$container))
|
|
113
|
+
) {
|
|
114
|
+
acceptor({
|
|
115
|
+
node,
|
|
116
|
+
property: 'key',
|
|
117
|
+
type: SemanticTokenTypes.property
|
|
118
|
+
})
|
|
119
|
+
}
|
|
89
120
|
if (
|
|
90
121
|
ast.isColorProperty(node)
|
|
91
122
|
|| ast.isShapeProperty(node)
|
|
@@ -93,6 +124,11 @@ export class LikeC4SemanticTokenProvider extends AbstractSemanticTokenProvider {
|
|
|
93
124
|
|| ast.isLineProperty(node)
|
|
94
125
|
|| ast.isBorderProperty(node)
|
|
95
126
|
) {
|
|
127
|
+
acceptor({
|
|
128
|
+
node,
|
|
129
|
+
property: 'key',
|
|
130
|
+
type: SemanticTokenTypes.property
|
|
131
|
+
})
|
|
96
132
|
acceptor({
|
|
97
133
|
node,
|
|
98
134
|
property: 'value',
|
|
@@ -100,24 +136,42 @@ export class LikeC4SemanticTokenProvider extends AbstractSemanticTokenProvider {
|
|
|
100
136
|
})
|
|
101
137
|
}
|
|
102
138
|
if (ast.isOpacityProperty(node)) {
|
|
139
|
+
acceptor({
|
|
140
|
+
node,
|
|
141
|
+
property: 'key',
|
|
142
|
+
type: SemanticTokenTypes.property
|
|
143
|
+
})
|
|
103
144
|
acceptor({
|
|
104
145
|
node,
|
|
105
146
|
property: 'value',
|
|
106
147
|
type: SemanticTokenTypes.number
|
|
107
148
|
})
|
|
149
|
+
return
|
|
108
150
|
}
|
|
109
|
-
if (
|
|
151
|
+
if (
|
|
152
|
+
ast.isLinkProperty(node)
|
|
153
|
+
|| ast.isIconProperty(node)
|
|
154
|
+
|| ast.isElementStringProperty(node)
|
|
155
|
+
|| ast.isRelationStringProperty(node)
|
|
156
|
+
|| ast.isViewStringProperty(node)
|
|
157
|
+
) {
|
|
158
|
+
acceptor({
|
|
159
|
+
node,
|
|
160
|
+
property: 'key',
|
|
161
|
+
type: SemanticTokenTypes.property
|
|
162
|
+
})
|
|
110
163
|
acceptor({
|
|
111
164
|
node,
|
|
112
165
|
property: 'value',
|
|
113
166
|
type: SemanticTokenTypes.string
|
|
114
167
|
})
|
|
168
|
+
return
|
|
115
169
|
}
|
|
116
170
|
if (ast.isElement(node)) {
|
|
117
|
-
this.highlightAstElement(node, acceptor)
|
|
171
|
+
return this.highlightAstElement(node, acceptor)
|
|
118
172
|
}
|
|
119
173
|
if (ast.isLikeC4View(node)) {
|
|
120
|
-
this.highlightView(node, acceptor)
|
|
174
|
+
return this.highlightView(node, acceptor)
|
|
121
175
|
}
|
|
122
176
|
}
|
|
123
177
|
|
|
@@ -126,7 +180,10 @@ export class LikeC4SemanticTokenProvider extends AbstractSemanticTokenProvider {
|
|
|
126
180
|
node,
|
|
127
181
|
property: 'name',
|
|
128
182
|
type: SemanticTokenTypes.variable,
|
|
129
|
-
modifier: [
|
|
183
|
+
modifier: [
|
|
184
|
+
SemanticTokenModifiers.declaration,
|
|
185
|
+
SemanticTokenModifiers.readonly
|
|
186
|
+
]
|
|
130
187
|
})
|
|
131
188
|
acceptor({
|
|
132
189
|
node,
|
|
@@ -142,7 +199,11 @@ export class LikeC4SemanticTokenProvider extends AbstractSemanticTokenProvider {
|
|
|
142
199
|
node,
|
|
143
200
|
property: 'name',
|
|
144
201
|
type: SemanticTokenTypes.variable,
|
|
145
|
-
modifier: [
|
|
202
|
+
modifier: [
|
|
203
|
+
SemanticTokenModifiers.declaration,
|
|
204
|
+
SemanticTokenModifiers.readonly,
|
|
205
|
+
'local'
|
|
206
|
+
]
|
|
146
207
|
})
|
|
147
208
|
}
|
|
148
209
|
}
|
package/src/lsp/index.ts
CHANGED
|
@@ -7,7 +7,6 @@ import {
|
|
|
7
7
|
type StrictElementView,
|
|
8
8
|
type ViewID
|
|
9
9
|
} from '@likec4/core'
|
|
10
|
-
import { computeDynamicView, computeView, LikeC4ModelGraph } from '@likec4/graph'
|
|
11
10
|
import { deepEqual as eq } from 'fast-equals'
|
|
12
11
|
import type { URI, WorkspaceCache } from 'langium'
|
|
13
12
|
import { DocumentState, interruptAndCheck, type LangiumDocument, type LangiumDocuments } from 'langium'
|
|
@@ -17,6 +16,7 @@ import {
|
|
|
17
16
|
flatMap,
|
|
18
17
|
forEach,
|
|
19
18
|
isNullish,
|
|
19
|
+
isNumber,
|
|
20
20
|
isTruthy,
|
|
21
21
|
map,
|
|
22
22
|
mapToObj,
|
|
@@ -36,6 +36,7 @@ import type {
|
|
|
36
36
|
} from '../ast'
|
|
37
37
|
import { isParsedLikeC4LangiumDocument } from '../ast'
|
|
38
38
|
import { logError, logger, logWarnError } from '../logger'
|
|
39
|
+
import { computeDynamicView, computeView, LikeC4ModelGraph } from '../model-graph'
|
|
39
40
|
import type { LikeC4Services } from '../module'
|
|
40
41
|
import { printDocs } from '../utils/printDocs'
|
|
41
42
|
import { assignNavigateTo, resolveRelativePaths, resolveRulesExtendedViews } from '../view-utils'
|
|
@@ -87,7 +88,7 @@ function buildModel(services: LikeC4Services, docs: ParsedLikeC4LangiumDocument[
|
|
|
87
88
|
...(icon && { icon }),
|
|
88
89
|
style: {
|
|
89
90
|
...(border && { border }),
|
|
90
|
-
...(opacity && { opacity })
|
|
91
|
+
...(isNumber(opacity) && { opacity })
|
|
91
92
|
},
|
|
92
93
|
links: links ? resolveLinks(doc, links) : null,
|
|
93
94
|
tags: tags ?? null,
|
|
@@ -169,43 +170,6 @@ function buildModel(services: LikeC4Services, docs: ParsedLikeC4LangiumDocument[
|
|
|
169
170
|
mapToObj(r => [r.id, r])
|
|
170
171
|
)
|
|
171
172
|
|
|
172
|
-
// const toElementView = (view: ParsedAstElementView, doc: LangiumDocument): c4.ElementView => {
|
|
173
|
-
// let { astPath, rules, title, description, tags, links, id, __, ...model } = view
|
|
174
|
-
|
|
175
|
-
// if ('viewOf' in view) {
|
|
176
|
-
// title ??= elements[view.viewOf]?.title ?? null
|
|
177
|
-
// }
|
|
178
|
-
// if (!title && view.id === 'index') {
|
|
179
|
-
// title = 'Landscape view'
|
|
180
|
-
// }
|
|
181
|
-
// return {
|
|
182
|
-
// __,
|
|
183
|
-
// id,
|
|
184
|
-
// ...model,
|
|
185
|
-
// title,
|
|
186
|
-
// description,
|
|
187
|
-
// tags,
|
|
188
|
-
// links: links ? resolveLinks(doc, links) : null,
|
|
189
|
-
// docUri: '',
|
|
190
|
-
// rules
|
|
191
|
-
// }
|
|
192
|
-
// }
|
|
193
|
-
|
|
194
|
-
// const toDynamicView = (view: ParsedAstDynamicView, doc: LangiumDocument): c4.DynamicView => {
|
|
195
|
-
// let { rules, steps, title, description, tags, links, id, __ } = view
|
|
196
|
-
// return {
|
|
197
|
-
// __,
|
|
198
|
-
// id,
|
|
199
|
-
// title,
|
|
200
|
-
// description,
|
|
201
|
-
// tags,
|
|
202
|
-
// links: links ? resolveLinks(doc, links) : null,
|
|
203
|
-
// docUri: '',
|
|
204
|
-
// rules,
|
|
205
|
-
// steps
|
|
206
|
-
// }
|
|
207
|
-
// }
|
|
208
|
-
|
|
209
173
|
const toC4View = (doc: LangiumDocument) => {
|
|
210
174
|
const docUri = doc.uri.toString()
|
|
211
175
|
return (parsedAstView: ParsedAstView): c4.View => {
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { type c4, InvalidModelError, invariant, isNonEmptyArray, nonexhaustive } from '@likec4/core'
|
|
2
2
|
import type { AstNode, LangiumDocument } from 'langium'
|
|
3
|
-
import { AstUtils } from 'langium'
|
|
3
|
+
import { AstUtils, CstUtils } from 'langium'
|
|
4
4
|
import { isTruthy } from 'remeda'
|
|
5
5
|
import stripIndent from 'strip-indent'
|
|
6
6
|
import type {
|
|
@@ -29,6 +29,7 @@ import { elementRef, getFqnElementRef } from '../elementRef'
|
|
|
29
29
|
import { logError, logger, logWarnError } from '../logger'
|
|
30
30
|
import type { LikeC4Services } from '../module'
|
|
31
31
|
import { stringHash } from '../utils'
|
|
32
|
+
import { deserializeFromComment } from '../view-utils/manual-layout'
|
|
32
33
|
import type { FqnIndex } from './fqn-index'
|
|
33
34
|
|
|
34
35
|
const { getDocument } = AstUtils
|
|
@@ -380,6 +381,14 @@ export class LikeC4ModelParser {
|
|
|
380
381
|
nonexhaustive(astRule)
|
|
381
382
|
}
|
|
382
383
|
|
|
384
|
+
private parseViewManualLaout(node: ast.DynamicView | ast.ElementView): c4.ViewManualLayout | undefined {
|
|
385
|
+
const commentNode = CstUtils.findCommentNode(node.$cstNode, ['BLOCK_COMMENT'])
|
|
386
|
+
if (!commentNode) {
|
|
387
|
+
return undefined
|
|
388
|
+
}
|
|
389
|
+
return deserializeFromComment(commentNode.text)
|
|
390
|
+
}
|
|
391
|
+
|
|
383
392
|
private parseDynamicStep(node: ast.DynamicViewStep): c4.DynamicViewStep {
|
|
384
393
|
const sourceEl = elementRef(node.source)
|
|
385
394
|
if (!sourceEl) {
|
|
@@ -435,11 +444,12 @@ export class LikeC4ModelParser {
|
|
|
435
444
|
const tags = this.convertTags(body)
|
|
436
445
|
const links = body.props.filter(ast.isLinkProperty).map(p => p.value)
|
|
437
446
|
|
|
447
|
+
const manualLayout = this.parseViewManualLaout(astNode)
|
|
448
|
+
|
|
438
449
|
const view: ParsedAstElementView = {
|
|
439
450
|
__: 'element',
|
|
440
451
|
id: id as c4.ViewID,
|
|
441
452
|
astPath,
|
|
442
|
-
...(viewOf && { viewOf }),
|
|
443
453
|
title,
|
|
444
454
|
description,
|
|
445
455
|
tags,
|
|
@@ -451,7 +461,9 @@ export class LikeC4ModelParser {
|
|
|
451
461
|
logWarnError(e)
|
|
452
462
|
return []
|
|
453
463
|
}
|
|
454
|
-
})
|
|
464
|
+
}),
|
|
465
|
+
...(viewOf && { viewOf }),
|
|
466
|
+
...(manualLayout && { manualLayout })
|
|
455
467
|
}
|
|
456
468
|
ViewOps.writeId(astNode, view.id)
|
|
457
469
|
|
|
@@ -489,6 +501,8 @@ export class LikeC4ModelParser {
|
|
|
489
501
|
|
|
490
502
|
ViewOps.writeId(astNode, id as c4.ViewID)
|
|
491
503
|
|
|
504
|
+
const manualLayout = this.parseViewManualLaout(astNode)
|
|
505
|
+
|
|
492
506
|
return {
|
|
493
507
|
__: 'dynamic',
|
|
494
508
|
id: id as c4.ViewID,
|
|
@@ -553,7 +567,8 @@ export class LikeC4ModelParser {
|
|
|
553
567
|
logWarnError(e)
|
|
554
568
|
}
|
|
555
569
|
return acc
|
|
556
|
-
}, [] as c4.DynamicViewStep[])
|
|
570
|
+
}, [] as c4.DynamicViewStep[]),
|
|
571
|
+
...(manualLayout && { manualLayout })
|
|
557
572
|
}
|
|
558
573
|
}
|
|
559
574
|
|