@likec4/language-server 1.6.1 → 1.7.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.
Files changed (51) hide show
  1. package/contrib/likec4.tmLanguage.json +1 -1
  2. package/package.json +23 -19
  3. package/src/Rpc.ts +1 -1
  4. package/src/ast.ts +34 -9
  5. package/src/{browser/index.ts → browser.ts} +4 -1
  6. package/src/generated/ast.ts +498 -152
  7. package/src/generated/grammar.ts +2 -2
  8. package/src/generated/module.ts +1 -1
  9. package/src/index.ts +1 -1
  10. package/src/like-c4.langium +116 -44
  11. package/src/logger.ts +76 -55
  12. package/src/lsp/DocumentLinkProvider.ts +1 -1
  13. package/src/lsp/DocumentSymbolProvider.ts +1 -1
  14. package/src/lsp/HoverProvider.ts +1 -1
  15. package/src/lsp/SemanticTokenProvider.ts +54 -26
  16. package/src/model/model-builder.ts +11 -8
  17. package/src/model/model-locator.ts +12 -25
  18. package/src/model/model-parser-where.ts +75 -0
  19. package/src/model/model-parser.ts +168 -68
  20. package/src/model-change/ModelChanges.ts +2 -3
  21. package/src/model-change/changeElementStyle.ts +4 -1
  22. package/src/model-change/changeViewLayout.ts +8 -8
  23. package/src/model-change/saveManualLayout.ts +4 -6
  24. package/src/model-graph/LikeC4ModelGraph.ts +50 -48
  25. package/src/model-graph/compute-view/__test__/fixture.ts +41 -16
  26. package/src/model-graph/compute-view/compute.ts +135 -69
  27. package/src/model-graph/compute-view/predicates.ts +232 -136
  28. package/src/model-graph/dynamic-view/__test__/fixture.ts +5 -1
  29. package/src/model-graph/dynamic-view/compute.ts +50 -41
  30. package/src/model-graph/utils/applyCustomElementProperties.ts +31 -29
  31. package/src/model-graph/utils/applyCustomRelationProperties.ts +52 -15
  32. package/src/model-graph/utils/elementExpressionToPredicate.ts +8 -3
  33. package/src/module.ts +4 -18
  34. package/src/{node/index.ts → node.ts} +1 -1
  35. package/src/protocol.ts +2 -2
  36. package/src/shared/NodeKindProvider.ts +4 -2
  37. package/src/test/setup.ts +13 -0
  38. package/src/test/testServices.ts +1 -1
  39. package/src/validation/dynamic-view-rule.ts +12 -12
  40. package/src/validation/index.ts +6 -6
  41. package/src/validation/relation.ts +1 -1
  42. package/src/validation/view-predicates/{custom-element-expr.ts → element-with.ts} +11 -10
  43. package/src/validation/view-predicates/expanded-element.ts +2 -10
  44. package/src/validation/view-predicates/incoming.ts +1 -1
  45. package/src/validation/view-predicates/index.ts +2 -2
  46. package/src/validation/view-predicates/outgoing.ts +1 -1
  47. package/src/validation/view-predicates/{custom-relation-expr.ts → relation-with.ts} +2 -2
  48. package/src/validation/view.ts +8 -9
  49. package/src/view-utils/manual-layout.ts +65 -72
  50. package/src/view-utils/resolve-relative-paths.ts +28 -17
  51. package/src/view-utils/view-hash.ts +33 -0
@@ -111,18 +111,24 @@ ExtendElementBody: '{'
111
111
 
112
112
  //
113
113
  FqnElementRef:
114
- el=[Element] ({infer FqnElementRef.parent=current} dot=StickyDot el=[Element])*;
114
+ el=[Element:Id] ({infer FqnElementRef.parent=current} StickyDot el=[Element:Id])*;
115
115
 
116
116
  ElementRef:
117
- el=[Element] ({infer ElementRef.parent=current} dot=StickyDot el=[Element])*;
117
+ el=[Element:Id] ({infer ElementRef.parent=current} StickyDot el=[Element:Id])*;
118
118
 
119
119
  Tags:
120
- value+=[Tag:TagId] (','? value+=[Tag:TagId])* (';')?
120
+ (values+=[Tag:TagId])+ ({infer Tags.prev=current} ',' (values+=[Tag:TagId])*)* ';'?
121
121
  ;
122
122
 
123
123
  Relation:
124
124
  ExplicitRelation | ImplicitRelation;
125
125
 
126
+ ExplicitRelation:
127
+ source=ElementRef RelationFragment;
128
+
129
+ ImplicitRelation:
130
+ ('this' | 'it')? RelationFragment;
131
+
126
132
  fragment RelationFragment:
127
133
  ('->' | '-[' kind=[RelationshipKind] ']->' | kind=[RelationshipKind:DotId] )
128
134
  target=ElementRef
@@ -131,12 +137,6 @@ fragment RelationFragment:
131
137
  body=RelationBody?
132
138
  ;
133
139
 
134
- ExplicitRelation:
135
- source=ElementRef RelationFragment;
136
-
137
- ImplicitRelation:
138
- ('this' | 'it')? RelationFragment;
139
-
140
140
  RelationBody: '{'
141
141
  tags=Tags?
142
142
  props+=RelationProperty*
@@ -147,7 +147,7 @@ RelationProperty:
147
147
  RelationStringProperty | RelationStyleProperty | LinkProperty;
148
148
 
149
149
  RelationStringProperty:
150
- key='title' ':'? value=String ';'?;
150
+ key=('title' | 'technology' | 'description') ':'? value=String ';'?;
151
151
 
152
152
  RelationStyleProperty:
153
153
  key='style' '{'
@@ -160,24 +160,23 @@ RelationStyleProperty:
160
160
 
161
161
  ModelViews:
162
162
  name='views' '{'
163
- views+=(
164
- DynamicView |
165
- ElementView
166
- )*
163
+ views+=LikeC4ViewRule*
167
164
  '}';
168
165
 
169
166
  type LikeC4View = ElementView | DynamicView;
167
+ LikeC4ViewRule returns LikeC4View:
168
+ ElementView | DynamicView;
170
169
 
171
170
  ElementView:
172
171
  'view' name=Id? (
173
172
  'extends' extends=ElementViewRef |
174
173
  'of' viewOf=ElementRef
175
174
  )?
176
- body=ElementViewBody
175
+ body=ElementViewBody?
177
176
  ;
178
177
 
179
178
  DynamicView:
180
- 'dynamic' 'view' name=Id body=DynamicViewBody
179
+ 'dynamic' 'view' name=Id body=DynamicViewBody?
181
180
  ;
182
181
 
183
182
  ViewRef:
@@ -201,7 +200,7 @@ DynamicViewBody: '{'
201
200
  ;
202
201
 
203
202
 
204
- type StringProperty = ElementStringProperty| ViewStringProperty | RelationStringProperty;
203
+ type StringProperty = ElementStringProperty | ViewStringProperty | RelationStringProperty;
205
204
 
206
205
  ViewProperty:
207
206
  ViewStringProperty | LinkProperty
@@ -220,34 +219,65 @@ ViewRule:
220
219
  ;
221
220
 
222
221
  DynamicViewRule:
223
- DynamicViewRulePredicate |
222
+ DynamicViewIncludePredicate |
224
223
  ViewRuleStyle |
225
224
  ViewRuleAutoLayout
226
225
  ;
227
226
 
228
227
  DynamicViewStep:
229
- source=ElementRef (isBackward?='<-' | '->' | '-[' kind=[RelationshipKind] ']->' | kind=[RelationshipKind:DotId] ) target=ElementRef title=String?
228
+ source=ElementRef
229
+ (isBackward?='<-' | '->' | '-[' kind=[RelationshipKind] ']->' | kind=[RelationshipKind:DotId] )
230
+ target=ElementRef
231
+ title=String?
232
+ custom=CustomRelationProperties?
230
233
  ;
231
234
 
232
235
  ViewRulePredicate:
233
- {infer IncludePredicate} 'include' exprs=Expressions |
234
- {infer ExcludePredicate} 'exclude' exprs=Expressions
236
+ {infer IncludePredicate} 'include' predicates=Predicates |
237
+ {infer ExcludePredicate} 'exclude' predicates=Predicates
238
+ ;
239
+ Predicates:
240
+ value=Predicate ({infer Predicates.prev=current} ',' value=Predicate?)*
235
241
  ;
236
242
 
237
- // IncludePredicate:
238
- // 'include' expr=WithExpressions ({infer IncludePredicate.prev=current} ',' (expr=WithExpressions)?)*
239
- // ;
240
- // ExcludePredicate:
241
- // 'exclude' expr=WithExpressions ({infer ExcludePredicate.prev=current} ',' (expr=WithExpressions)?)*
242
- // ;
243
+ Predicate:
244
+ RelationPredicate |
245
+ ElementPredicate
246
+ ;
243
247
 
244
- Expressions:
245
- value=WithExpressions ({infer Expressions.prev=current} ',' (value=WithExpressions)?)*
248
+ ElementPredicate:
249
+ ElementPredicates;
250
+
251
+ ElementPredicates infers ElementPredicate:
252
+ ElementPredicateOrWhere ({infer ElementPredicateWith.subject=current} 'with' custom=CustomElementProperties?)?
246
253
  ;
247
254
 
248
- WithExpressions infers Expression:
249
- RelationExpression ({infer CustomRelationExpression.relation=current} 'with' custom=CustomRelationProperties)? |
250
- ElementExpression ({infer CustomElementExpression.target=current} 'with' custom=CustomElementProperties)?
255
+ ElementPredicateOrWhere:
256
+ ElementExpression ({infer ElementPredicateWhere.subject=current} 'where' where=WhereElementExpression?)?
257
+ ;
258
+
259
+ WhereElementExpression:
260
+ WhereElementOr
261
+ ;
262
+ WhereElementOr infers WhereElementExpression:
263
+ WhereElementAnd ({infer WhereBinaryExpression.left=current} operator='or' right=WhereElementAnd)*
264
+ ;
265
+ WhereElementAnd infers WhereElementExpression:
266
+ WhereElementPrimary ({infer WhereBinaryExpression.left=current} operator='and' right=WhereElementPrimary)*
267
+ ;
268
+
269
+ WhereElementPrimary infers WhereElementExpression:
270
+ '(' WhereElementExpression ')' |
271
+ WhereElementNegation |
272
+ WhereElement
273
+ ;
274
+
275
+ WhereElementNegation:
276
+ 'not' value=WhereElementExpression;
277
+
278
+ WhereElement:
279
+ {infer WhereElementTag} 'tag' EqOperator value=[Tag:TagId]? |
280
+ {infer WhereElementKind} 'kind' EqOperator value=[ElementKind]?
251
281
  ;
252
282
 
253
283
  ElementExpression:
@@ -268,6 +298,48 @@ ElementDescedantsExpression infers ElementExpression:
268
298
  )?
269
299
  ;
270
300
 
301
+ RelationPredicate:
302
+ RelationPredicates
303
+ ;
304
+
305
+ RelationPredicates infers RelationPredicate:
306
+ RelationPredicateOrWhere ({infer RelationPredicateWith.subject=current} 'with' custom=CustomRelationProperties?)?
307
+ ;
308
+
309
+ RelationPredicateOrWhere:
310
+ RelationExpression ({infer RelationPredicateWhere.subject=current} 'where' where=WhereRelationExpression?)?
311
+ ;
312
+
313
+ WhereRelationExpression:
314
+ WhereRelationOr
315
+ ;
316
+
317
+ WhereRelationOr infers WhereRelationExpression:
318
+ WhereRelationAnd ({infer WhereBinaryExpression.left=current} operator='or' right=WhereRelationAnd)*
319
+ ;
320
+ WhereRelationAnd infers WhereRelationExpression:
321
+ WhereRelationPrimary ({infer WhereBinaryExpression.left=current} operator='and' right=WhereRelationPrimary)*
322
+ ;
323
+
324
+ WhereRelationPrimary infers WhereRelationExpression:
325
+ '(' WhereRelationExpression ')' |
326
+ WhereRelationNegation |
327
+ WhereRelation
328
+ ;
329
+
330
+ WhereRelationNegation:
331
+ 'not' value=WhereRelationExpression;
332
+
333
+ WhereRelation:
334
+ {infer WhereRelationTag} 'tag' EqOperator value=[Tag:TagId]? |
335
+ {infer WhereRelationKind} 'kind' EqOperator value=[RelationshipKind]?
336
+ ;
337
+
338
+ type WhereTagEqual = WhereElementTag | WhereRelationTag;
339
+ type WhereKindEqual = WhereElementKind | WhereRelationKind;
340
+
341
+ type WhereExpression = WhereElementExpression | WhereRelationExpression;
342
+
271
343
  RelationExpression:
272
344
  InOutRelationExpressions |
273
345
  DirectedRelationExpressions
@@ -294,16 +366,12 @@ ElementExpressionsIterator:
294
366
  value=ElementExpression ({infer ElementExpressionsIterator.prev=current} ',' (value=ElementExpression)?)*
295
367
  ;
296
368
 
297
- DynamicViewRulePredicate:
298
- 'include' exprs=DynamicViewRulePredicateIterator
369
+ DynamicViewIncludePredicate:
370
+ 'include' predicates=DynamicViewPredicateIterator
299
371
  ;
300
372
 
301
- DynamicViewRulePredicateIterator:
302
- value=DynamicViewElementExpressions ({infer DynamicViewRulePredicateIterator.prev=current} ',' (value=DynamicViewElementExpressions)?)*
303
- ;
304
-
305
- DynamicViewElementExpressions infers DynamicViewElementExpression:
306
- ElementExpression ({infer CustomElementExpression.target=current} 'with' custom=CustomElementProperties)?
373
+ DynamicViewPredicateIterator:
374
+ value=ElementPredicate ({infer DynamicViewPredicateIterator.prev=current} ',' (value=ElementPredicate)?)*
307
375
  ;
308
376
 
309
377
  ViewRuleStyle:
@@ -407,13 +475,10 @@ ElementShape returns string:
407
475
 
408
476
  IconId returns string:
409
477
  LIB_ICON;
410
- // ('aws:' | 'gcp:' | 'tech:') IdTerminal;
411
478
 
412
479
  Uri returns string:
413
480
  URI_WITH_SCHEMA | URI_RELATIVE;
414
481
 
415
- // Percent returns string: PERCENT;
416
-
417
482
  TagId returns string:
418
483
  Hash Id;
419
484
 
@@ -423,6 +488,13 @@ DotId returns string:
423
488
  Id returns string:
424
489
  IdTerminal | ElementShape | ThemeColor | ArrowType | LineOptions | 'element' | 'model';
425
490
 
491
+ fragment EqOperator:
492
+ (
493
+ operator=(Eq | NotEqual) |
494
+ operator="is" not?='not'?
495
+ )
496
+ ;
497
+
426
498
  fragment IsEqual:
427
499
  isEqual?=Eq | NotEqual;
428
500
 
@@ -447,7 +519,7 @@ hidden terminal WS: /\s+/;
447
519
  //terminal LineStartWithDash: /(?<=([\r?\n][^\S\r\n]*))-/;
448
520
 
449
521
  // LibIcons
450
- terminal LIB_ICON: /\b(aws|gcp|tech):[-\w]*/;
522
+ terminal LIB_ICON: /(aws|gcp|tech):[-\w]*/;
451
523
 
452
524
  terminal URI_WITH_SCHEMA: /\w+:\/\/\S+/;
453
525
  terminal URI_RELATIVE: /\.{0,2}\/[^\/]\S+/;
package/src/logger.ts CHANGED
@@ -1,68 +1,89 @@
1
1
  /* eslint-disable @typescript-eslint/no-explicit-any */
2
- import { normalizeError } from '@likec4/core'
2
+ import { type ConsolaReporter, LogLevels, rootLogger as root } from '@likec4/log'
3
+ import type { Connection } from 'vscode-languageserver'
3
4
 
4
- /* eslint-disable @typescript-eslint/no-redundant-type-constituents */
5
- let isSilent = false
5
+ export const logger = root.withTag('lsp')
6
6
 
7
- export const logger = {
8
- trace(message: string) {
9
- if (isSilent) return
10
- console.trace(message)
11
- },
12
- debug(message: string) {
13
- if (isSilent) return
14
- console.debug(message)
15
- },
16
- info(message: string) {
17
- if (isSilent) return
18
- console.info(message)
19
- },
20
- warn(message: unknown) {
21
- if (isSilent) return
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}`)
28
- },
29
- error(message: unknown) {
30
- if (isSilent) return
31
- if (typeof message === 'string' || message instanceof Error) {
32
- console.error(message)
33
- return
34
- }
35
- const error = normalizeError(message)
36
- console.error(`${error.name}: ${error.message}`, error)
37
- },
38
- silent(silent = true) {
39
- isSilent = silent
40
- }
7
+ export function logError(err: unknown): void {
8
+ logger.error(err)
41
9
  }
42
10
 
43
- export type Logger = typeof logger
44
-
45
- export function logError(err: unknown): void {
46
- if (typeof err === 'string') {
47
- logger.error(err)
48
- return
49
- }
11
+ export function logWarnError(err: unknown): void {
50
12
  if (err instanceof Error) {
51
- logger.error(err.stack ?? err.message)
13
+ logger.warn(err.stack ?? err.message)
52
14
  return
53
15
  }
54
- logger.error(normalizeError(err))
16
+ logger.warn(err)
55
17
  }
56
18
 
57
- export function logWarnError(err: unknown): void {
58
- if (typeof err === 'string') {
59
- logger.warn(err)
60
- return
19
+ export function setLogLevel(level: keyof typeof LogLevels): void {
20
+ logger.level = LogLevels[level]
21
+ }
22
+
23
+ export function logErrorToTelemetry(connection: Connection): void {
24
+ const reporter: ConsolaReporter = {
25
+ log: ({ level, ...logObj }, ctx) => {
26
+ if (level !== LogLevels.error && level !== LogLevels.fatal) {
27
+ return
28
+ }
29
+ const tag = logObj.tag || ''
30
+ const parts = logObj.args.map((arg) => {
31
+ if (arg && typeof arg.stack === 'string') {
32
+ return arg.message + '\n' + arg.stack
33
+ }
34
+ if (typeof arg === 'string') {
35
+ return arg
36
+ }
37
+ return String(arg)
38
+ })
39
+ if (tag) {
40
+ parts.unshift(`[${tag}]`)
41
+ }
42
+ const message = parts.join(' ')
43
+ connection.telemetry.logEvent({ eventName: 'error', error: message })
44
+ }
61
45
  }
62
- if (err instanceof Error) {
63
- logger.warn(err.stack ?? err.message)
64
- return
46
+ root.addReporter(reporter)
47
+ logger.setReporters(root.options.reporters)
48
+ }
49
+
50
+ export function logToLspConnection(connection: Connection): void {
51
+ const reporter: ConsolaReporter = {
52
+ log: ({ level, ...logObj }, ctx) => {
53
+ const tag = logObj.tag || ''
54
+ const parts = logObj.args.map((arg) => {
55
+ if (arg && typeof arg.stack === 'string') {
56
+ return arg.message + '\n' + arg.stack
57
+ }
58
+ if (typeof arg === 'string') {
59
+ return arg
60
+ }
61
+ return String(arg)
62
+ })
63
+ if (tag) {
64
+ parts.unshift(`[${tag}]`)
65
+ }
66
+ const message = parts.join(' ')
67
+ switch (true) {
68
+ case level >= LogLevels.debug: {
69
+ connection.console.debug(message)
70
+ break
71
+ }
72
+ case level >= LogLevels.log: {
73
+ connection.console.info(message)
74
+ break
75
+ }
76
+ case level >= LogLevels.warn: {
77
+ connection.console.warn(message)
78
+ break
79
+ }
80
+ case level >= LogLevels.fatal: {
81
+ connection.console.error(message)
82
+ break
83
+ }
84
+ }
85
+ }
65
86
  }
66
- const error = normalizeError(err)
67
- logger.warn(`${error.name}: ${error.message}`)
87
+ root.addReporter(reporter)
88
+ logger.setReporters(root.options.reporters)
68
89
  }
@@ -2,7 +2,7 @@ import type { LangiumDocument, MaybePromise } from 'langium'
2
2
  import { AstUtils, GrammarUtils } from 'langium'
3
3
  import type { DocumentLinkProvider } from 'langium/lsp'
4
4
  import { hasProtocol, isRelative, withBase } from 'ufo'
5
- import type { DocumentLink, DocumentLinkParams } from 'vscode-languageserver-protocol'
5
+ import type { DocumentLink, DocumentLinkParams } from 'vscode-languageserver'
6
6
  import { ast, isParsedLikeC4LangiumDocument } from '../ast'
7
7
  import { logError } from '../logger'
8
8
  import type { LikeC4Services } from '../module'
@@ -2,7 +2,7 @@ import { nonexhaustive } from '@likec4/core'
2
2
  import { type AstNode, GrammarUtils, type MaybePromise } from 'langium'
3
3
  import type { DocumentSymbolProvider, NodeKindProvider } from 'langium/lsp'
4
4
  import { filter, isEmpty, isTruthy, map, pipe } from 'remeda'
5
- import { type DocumentSymbol, SymbolKind } from 'vscode-languageserver-protocol'
5
+ import { type DocumentSymbol, SymbolKind } from 'vscode-languageserver-types'
6
6
  import { ast, type LikeC4LangiumDocument } from '../ast'
7
7
  import { getFqnElementRef } from '../elementRef'
8
8
  import { logError } from '../logger'
@@ -2,7 +2,7 @@ import { type AstNode, type MaybePromise } from 'langium'
2
2
  import { AstNodeHoverProvider } from 'langium/lsp'
3
3
  import { isTruthy } from 'remeda'
4
4
  import stripIndent from 'strip-indent'
5
- import type { Hover } from 'vscode-languageserver-protocol'
5
+ import type { Hover } from 'vscode-languageserver-types'
6
6
  import { ast } from '../ast'
7
7
  import type { LikeC4ModelLocator } from '../model'
8
8
  import type { LikeC4Services } from '../module'
@@ -1,7 +1,7 @@
1
1
  import type { AstNode } from 'langium'
2
2
  import { AbstractSemanticTokenProvider, type SemanticTokenAcceptor } from 'langium/lsp'
3
3
  import { isTruthy } from 'remeda'
4
- import { SemanticTokenModifiers, SemanticTokenTypes } from 'vscode-languageserver-protocol'
4
+ import { SemanticTokenModifiers, SemanticTokenTypes } from 'vscode-languageserver-types'
5
5
  import { ast } from '../ast'
6
6
 
7
7
  export class LikeC4SemanticTokenProvider extends AbstractSemanticTokenProvider {
@@ -27,6 +27,14 @@ export class LikeC4SemanticTokenProvider extends AbstractSemanticTokenProvider {
27
27
  return 'prune'
28
28
  }
29
29
 
30
+ if (ast.isOutgoingRelationExpression(node) && 'kind' in node) {
31
+ acceptor({
32
+ node,
33
+ property: 'kind',
34
+ type: SemanticTokenTypes.function
35
+ })
36
+ return
37
+ }
30
38
  if (ast.isRelation(node) && 'kind' in node) {
31
39
  acceptor({
32
40
  node,
@@ -60,7 +68,27 @@ export class LikeC4SemanticTokenProvider extends AbstractSemanticTokenProvider {
60
68
  SemanticTokenModifiers.readonly
61
69
  ]
62
70
  })
63
- return 'prune'
71
+ return
72
+ }
73
+ if (ast.isWhereRelationKind(node) && isTruthy(node.value)) {
74
+ acceptor({
75
+ node,
76
+ property: 'value',
77
+ type: SemanticTokenTypes.function
78
+ })
79
+ return
80
+ }
81
+ if ((ast.isWhereElement(node) || ast.isWhereRelation(node)) && isTruthy(node.value)) {
82
+ acceptor({
83
+ node,
84
+ property: 'value',
85
+ type: SemanticTokenTypes.type,
86
+ modifier: [
87
+ SemanticTokenModifiers.definition,
88
+ SemanticTokenModifiers.readonly
89
+ ]
90
+ })
91
+ return
64
92
  }
65
93
  if (ast.isElementKindExpression(node) && isTruthy(node.kind)) {
66
94
  acceptor({
@@ -102,12 +130,11 @@ export class LikeC4SemanticTokenProvider extends AbstractSemanticTokenProvider {
102
130
  })
103
131
  }
104
132
  if (ast.isTags(node)) {
105
- acceptor({
133
+ return acceptor({
106
134
  node,
107
- property: 'value',
135
+ property: 'values',
108
136
  type: SemanticTokenTypes.interface
109
137
  })
110
- return
111
138
  }
112
139
  if (ast.isTag(node)) {
113
140
  return acceptor({
@@ -127,25 +154,6 @@ export class LikeC4SemanticTokenProvider extends AbstractSemanticTokenProvider {
127
154
  type: SemanticTokenTypes.property
128
155
  })
129
156
  }
130
- if (
131
- ast.isColorProperty(node)
132
- || ast.isShapeProperty(node)
133
- || ast.isArrowProperty(node)
134
- || ast.isLineProperty(node)
135
- || ast.isBorderProperty(node)
136
- ) {
137
- acceptor({
138
- node,
139
- property: 'key',
140
- type: SemanticTokenTypes.property
141
- })
142
- acceptor({
143
- node,
144
- property: 'value',
145
- type: SemanticTokenTypes.enum
146
- })
147
- return 'prune'
148
- }
149
157
  if (ast.isOpacityProperty(node)) {
150
158
  acceptor({
151
159
  node,
@@ -169,6 +177,13 @@ export class LikeC4SemanticTokenProvider extends AbstractSemanticTokenProvider {
169
177
  property: 'key',
170
178
  type: SemanticTokenTypes.property
171
179
  })
180
+ if ('value' in node) {
181
+ acceptor({
182
+ node,
183
+ property: 'value',
184
+ type: SemanticTokenTypes.string
185
+ })
186
+ }
172
187
  if (ast.isIconProperty(node) && node.libicon) {
173
188
  acceptor({
174
189
  node,
@@ -176,14 +191,27 @@ export class LikeC4SemanticTokenProvider extends AbstractSemanticTokenProvider {
176
191
  type: SemanticTokenTypes.enum
177
192
  })
178
193
  }
194
+ return 'prune'
195
+ }
196
+ if (
197
+ ast.isColorProperty(node)
198
+ || ast.isShapeProperty(node)
199
+ || ast.isArrowProperty(node)
200
+ || ast.isLineProperty(node)
201
+ || ast.isBorderProperty(node)
202
+ ) {
203
+ acceptor({
204
+ node,
205
+ property: 'key',
206
+ type: SemanticTokenTypes.property
207
+ })
179
208
  if ('value' in node) {
180
209
  acceptor({
181
210
  node,
182
211
  property: 'value',
183
- type: SemanticTokenTypes.string
212
+ type: SemanticTokenTypes.enum
184
213
  })
185
214
  }
186
-
187
215
  return 'prune'
188
216
  }
189
217
  if (ast.isElement(node)) {
@@ -8,8 +8,8 @@ import {
8
8
  type ViewID
9
9
  } from '@likec4/core'
10
10
  import { deepEqual as eq } from 'fast-equals'
11
- import type { URI, WorkspaceCache } from 'langium'
12
- import { DocumentState, interruptAndCheck, type LangiumDocument, type LangiumDocuments } from 'langium'
11
+ import type { Cancellation, LangiumDocument, LangiumDocuments, URI, WorkspaceCache } from 'langium'
12
+ import { Disposable, DocumentState, interruptAndCheck } from 'langium'
13
13
  import {
14
14
  filter,
15
15
  find,
@@ -26,7 +26,6 @@ import {
26
26
  sort,
27
27
  values
28
28
  } from 'remeda'
29
- import { type CancellationToken, Disposable } from 'vscode-languageserver-protocol'
30
29
  import type {
31
30
  ParsedAstElement,
32
31
  ParsedAstRelation,
@@ -245,7 +244,6 @@ function buildModel(services: LikeC4Services, docs: ParsedLikeC4LangiumDocument[
245
244
  views
246
245
  }
247
246
  }
248
-
249
247
  const RAW_MODEL_CACHE = 'LikeC4RawModel'
250
248
  const MODEL_CACHE = 'LikeC4Model'
251
249
 
@@ -282,7 +280,7 @@ export class LikeC4ModelBuilder {
282
280
  logger.debug(`[ModelBuilder] Created`)
283
281
  }
284
282
 
285
- public async buildModel(cancelToken?: CancellationToken): Promise<c4.LikeC4Model | null> {
283
+ public async buildModel(cancelToken?: Cancellation.CancellationToken): Promise<c4.LikeC4Model | null> {
286
284
  return await this.services.shared.workspace.WorkspaceLock.read(async () => {
287
285
  if (cancelToken) {
288
286
  await interruptAndCheck(cancelToken)
@@ -302,7 +300,9 @@ export class LikeC4ModelBuilder {
302
300
 
303
301
  private previousViews: Record<ViewID, c4.ComputedView> = {}
304
302
 
305
- public async buildComputedModel(cancelToken?: CancellationToken): Promise<c4.LikeC4ComputedModel | null> {
303
+ public async buildComputedModel(
304
+ cancelToken?: Cancellation.CancellationToken
305
+ ): Promise<c4.LikeC4ComputedModel | null> {
306
306
  const model = await this.buildModel(cancelToken)
307
307
  if (!model) {
308
308
  return null
@@ -342,7 +342,10 @@ export class LikeC4ModelBuilder {
342
342
  })
343
343
  }
344
344
 
345
- public async computeView(viewId: ViewID, cancelToken?: CancellationToken): Promise<c4.ComputedView | null> {
345
+ public async computeView(
346
+ viewId: ViewID,
347
+ cancelToken?: Cancellation.CancellationToken
348
+ ): Promise<c4.ComputedView | null> {
346
349
  const model = await this.buildModel(cancelToken)
347
350
  const view = model?.views[viewId]
348
351
  if (!view) {
@@ -361,12 +364,12 @@ export class LikeC4ModelBuilder {
361
364
  logError(result.error)
362
365
  return null
363
366
  }
367
+ let computedView = result.view
364
368
 
365
369
  const allElementViews = values(model.views).filter(
366
370
  (v): v is ScopedElementView => isScopedElementView(v) && v.id !== viewId
367
371
  )
368
372
 
369
- let computedView = result.view
370
373
  computedView.nodes.forEach(node => {
371
374
  if (!node.navigateTo) {
372
375
  // find first element view that is not the current one