@likec4/language-server 1.8.0 → 1.9.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.
Files changed (83) hide show
  1. package/contrib/likec4.tmLanguage.json +1 -1
  2. package/dist/browser.cjs +21 -0
  3. package/dist/browser.d.cts +22 -0
  4. package/dist/browser.d.mts +22 -0
  5. package/dist/browser.d.ts +22 -0
  6. package/dist/browser.mjs +19 -0
  7. package/dist/index.cjs +10 -0
  8. package/dist/index.d.cts +18 -0
  9. package/dist/index.d.mts +18 -0
  10. package/dist/index.d.ts +18 -0
  11. package/dist/index.mjs +1 -0
  12. package/dist/likec4lib.cjs +961 -0
  13. package/dist/likec4lib.d.cts +6 -0
  14. package/dist/likec4lib.d.mts +6 -0
  15. package/dist/likec4lib.d.ts +6 -0
  16. package/dist/likec4lib.mjs +957 -0
  17. package/dist/model-graph/index.cjs +10 -0
  18. package/dist/model-graph/index.d.cts +79 -0
  19. package/dist/model-graph/index.d.mts +79 -0
  20. package/dist/model-graph/index.d.ts +79 -0
  21. package/dist/model-graph/index.mjs +1 -0
  22. package/dist/node.cjs +18 -0
  23. package/dist/node.d.cts +20 -0
  24. package/dist/node.d.mts +20 -0
  25. package/dist/node.d.ts +20 -0
  26. package/dist/node.mjs +16 -0
  27. package/dist/protocol.cjs +25 -0
  28. package/dist/protocol.d.cts +43 -0
  29. package/dist/protocol.d.mts +43 -0
  30. package/dist/protocol.d.ts +43 -0
  31. package/dist/protocol.mjs +17 -0
  32. package/dist/shared/language-server.86lmJ8ZN.d.cts +1194 -0
  33. package/dist/shared/language-server.B1TZgyoH.cjs +5371 -0
  34. package/dist/shared/language-server.CCB4ESN5.mjs +1606 -0
  35. package/dist/shared/language-server.CFTY6j4e.d.mts +1194 -0
  36. package/dist/shared/language-server.D0bOlrCi.cjs +1619 -0
  37. package/dist/shared/language-server.Q-wtPShM.mjs +5360 -0
  38. package/dist/shared/language-server.RjhrBZS0.d.ts +1194 -0
  39. package/package.json +35 -20
  40. package/src/ast.ts +44 -32
  41. package/src/browser.ts +0 -3
  42. package/src/elementRef.ts +1 -1
  43. package/src/generated/ast.ts +105 -86
  44. package/src/generated/grammar.ts +1 -1
  45. package/src/generated-lib/icons.ts +1 -1
  46. package/src/like-c4.langium +30 -18
  47. package/src/likec4lib.ts +2 -3
  48. package/src/logger.ts +9 -1
  49. package/src/lsp/RenameProvider.ts +8 -0
  50. package/src/lsp/SemanticTokenProvider.ts +19 -1
  51. package/src/lsp/index.ts +1 -0
  52. package/src/model/fqn-computation.ts +33 -23
  53. package/src/model/fqn-index.ts +5 -20
  54. package/src/model/model-builder.ts +147 -90
  55. package/src/model/model-locator.ts +1 -1
  56. package/src/model/model-parser-where.ts +3 -2
  57. package/src/model/model-parser.ts +57 -19
  58. package/src/model-graph/LikeC4ModelGraph.ts +42 -21
  59. package/src/model-graph/compute-view/__test__/fixture.ts +16 -14
  60. package/src/model-graph/compute-view/compute.ts +9 -6
  61. package/src/model-graph/compute-view/predicates.ts +3 -3
  62. package/src/model-graph/dynamic-view/__test__/fixture.ts +1 -0
  63. package/src/model-graph/dynamic-view/compute.ts +2 -1
  64. package/src/model-graph/utils/elementExpressionToPredicate.ts +1 -1
  65. package/src/model-graph/utils/sortNodes.ts +2 -6
  66. package/src/module.ts +23 -3
  67. package/src/protocol.ts +4 -5
  68. package/src/references/scope-computation.ts +10 -1
  69. package/src/references/scope-provider.ts +22 -9
  70. package/src/shared/NodeKindProvider.ts +73 -34
  71. package/src/test/setup.ts +3 -8
  72. package/src/utils/graphlib.ts +11 -0
  73. package/src/validation/_shared.ts +24 -0
  74. package/src/validation/element.ts +9 -9
  75. package/src/validation/index.ts +2 -1
  76. package/src/validation/relation.ts +45 -39
  77. package/src/validation/specification.ts +15 -2
  78. package/src/validation/view.ts +7 -0
  79. package/src/view-utils/manual-layout.ts +1 -1
  80. package/src/view-utils/resolve-extended-views.ts +19 -10
  81. package/src/view-utils/resolve-relative-paths.ts +5 -7
  82. package/src/view-utils/view-hash.ts +1 -1
  83. package/src/reset.d.ts +0 -2
@@ -3,14 +3,13 @@ import {
3
3
  commonAncestor,
4
4
  type Element,
5
5
  type Fqn,
6
- InvalidModelError,
7
6
  invariant,
8
7
  isSameHierarchy,
9
- isString,
10
8
  parentFqn,
11
9
  type Relation,
12
10
  type RelationID
13
11
  } from '@likec4/core'
12
+ import { isArray, isString } from 'remeda'
14
13
 
15
14
  type Params = {
16
15
  elements: Record<Fqn, Element>
@@ -25,7 +24,7 @@ type RelationEdge = {
25
24
  }
26
25
 
27
26
  type FqnOrElement = Fqn | Element
28
- type FqnsOrElements = Fqn[] | Element[]
27
+ type FqnsOrElements = ReadonlyArray<Fqn> | ReadonlyArray<Element>
29
28
 
30
29
  const RelationsSet = Set<Relation>
31
30
  const MapRelations = Map<Fqn, Set<Relation>>
@@ -37,9 +36,16 @@ function intersection<T>(a: Set<T>, b: Set<T>) {
37
36
  return new Set([...a].filter(value => b.has(value)))
38
37
  }
39
38
 
39
+ /**
40
+ * Used only for views calculations.
41
+ * Subject to change.
42
+ */
40
43
  export class LikeC4ModelGraph {
41
44
  #elements = new Map<Fqn, Element>()
42
- #children = new Map<Fqn, Fqn[]>()
45
+ // Parent element for given FQN
46
+ #parents = new Map<Fqn, Element>()
47
+ // Children elements for given FQN
48
+ #children = new Map<Fqn, Element[]>()
43
49
  #rootElements = new Set<Element>()
44
50
 
45
51
  #relations = new Map<RelationID, Relation>()
@@ -47,7 +53,7 @@ export class LikeC4ModelGraph {
47
53
  #incoming = new MapRelations()
48
54
  // Outgoing from an element or its descendants
49
55
  #outgoing = new MapRelations()
50
- // Relationships inside the element descendants
56
+ // Relationships inside the element, among descendants
51
57
  #internal = new MapRelations()
52
58
 
53
59
  #cacheAscendingSiblings = new Map<Fqn, Element[]>()
@@ -80,7 +86,7 @@ export class LikeC4ModelGraph {
80
86
  }
81
87
 
82
88
  public children(id: Fqn) {
83
- return this._childrenOf(id).flatMap(id => this.#elements.get(id) ?? [])
89
+ return this._childrenOf(id).slice()
84
90
  }
85
91
 
86
92
  // Get children or element itself if no children
@@ -93,19 +99,30 @@ export class LikeC4ModelGraph {
93
99
  public siblings(element: Fqn | Element) {
94
100
  const id = isString(element) ? element : element.id
95
101
  const parent = parentFqn(id)
96
- const fqns = parent ? this._childrenOf(parent) : [...this.#rootElements].map(e => e.id)
97
- return fqns.flatMap(fqn => (fqn !== id && this.#elements.get(fqn)) || [])
102
+ const siblings = parent ? this._childrenOf(parent) : this.rootElements
103
+ return siblings.filter(e => e.id !== id)
98
104
  }
99
105
 
100
- public ancestors(element: Fqn | Element) {
101
- const id = isString(element) ? element : element.id
102
- return ancestorsFqn(id).flatMap(id => this.#elements.get(id) ?? [])
106
+ /**
107
+ * Get all ancestor elements (i.e. parent, parent’s parent, etc.)
108
+ * (from closest to root)
109
+ */
110
+ public ancestors(element: Fqn | Element): Array<Element> {
111
+ let id = isString(element) ? element : element.id
112
+ const result = [] as Element[]
113
+ let parent
114
+ while (parent = this.#parents.get(id)) {
115
+ result.push(parent)
116
+ id = parent.id
117
+ }
118
+ return result as Array<Element>
103
119
  }
104
120
 
105
121
  /**
106
122
  * Resolve siblings of the element and its ancestors
123
+ * (from closest to root)
107
124
  */
108
- public ascendingSiblings(element: Fqn | Element) {
125
+ public ascendingSiblings(element: Fqn | Element): Array<Element> {
109
126
  const id = isString(element) ? element : element.id
110
127
  let siblings = this.#cacheAscendingSiblings.get(id)
111
128
  if (!siblings) {
@@ -121,7 +138,10 @@ export class LikeC4ModelGraph {
121
138
  /**
122
139
  * Resolve all RelationEdges between element and others (any direction)
123
140
  */
124
- public anyEdgesBetween(_element: Fqn | Element, others: Fqn[] | Element[]): RelationEdge[] {
141
+ public anyEdgesBetween(
142
+ _element: Fqn | Element,
143
+ others: ReadonlyArray<Fqn> | ReadonlyArray<Element>
144
+ ): Array<RelationEdge> {
125
145
  if (others.length === 0) {
126
146
  return []
127
147
  }
@@ -169,7 +189,7 @@ export class LikeC4ModelGraph {
169
189
  /**
170
190
  * Resolve all RelationEdges between elements (any direction)
171
191
  */
172
- public edgesWithin<T extends Fqn[] | Element[]>(elements: T): RelationEdge[] {
192
+ public edgesWithin<T extends Fqn[] | Element[]>(elements: T): Array<RelationEdge> {
173
193
  if (elements.length < 2) {
174
194
  return []
175
195
  }
@@ -190,8 +210,8 @@ export class LikeC4ModelGraph {
190
210
  _sources: FqnOrElement | FqnsOrElements,
191
211
  _targets: FqnOrElement | FqnsOrElements
192
212
  ) {
193
- const sources = Array.isArray(_sources) ? _sources : [_sources]
194
- const targets = Array.isArray(_targets) ? _targets : [_targets]
213
+ const sources = isArray(_sources) ? _sources : [_sources]
214
+ const targets = isArray(_targets) ? _targets : [_targets]
195
215
  if (sources.length === 0 || targets.length === 0) {
196
216
  return []
197
217
  }
@@ -226,12 +246,13 @@ export class LikeC4ModelGraph {
226
246
 
227
247
  private addElement(el: Element) {
228
248
  if (this.#elements.has(el.id)) {
229
- throw new InvalidModelError(`Element ${el.id} already exists`)
249
+ throw new Error(`Element ${el.id} already exists`)
230
250
  }
231
251
  this.#elements.set(el.id, el)
232
- const parent = parentFqn(el.id)
233
- if (parent) {
234
- this._childrenOf(parent).push(el.id)
252
+ const parentId = parentFqn(el.id)
253
+ if (parentId) {
254
+ this.#parents.set(el.id, this.element(parentId))
255
+ this._childrenOf(parentId).push(el)
235
256
  } else {
236
257
  this.#rootElements.add(el)
237
258
  }
@@ -239,7 +260,7 @@ export class LikeC4ModelGraph {
239
260
 
240
261
  private addRelation(rel: Relation) {
241
262
  if (this.#relations.has(rel.id)) {
242
- throw new InvalidModelError(`Relation ${rel.id} already exists`)
263
+ throw new Error(`Relation ${rel.id} already exists`)
243
264
  }
244
265
  this.#relations.set(rel.id, rel)
245
266
  this._incomingTo(rel.target).add(rel)
@@ -1,5 +1,6 @@
1
1
  import {
2
2
  type BorderStyle,
3
+ type Color,
3
4
  type ComputedView,
4
5
  type CustomElementExpr as C4CustomElementExpr,
5
6
  type CustomRelationExpr as C4CustomRelationExpr,
@@ -17,7 +18,6 @@ import {
17
18
  type RelationshipLineType,
18
19
  type RelationWhereExpr,
19
20
  type Tag,
20
- type ThemeColor,
21
21
  type ViewID,
22
22
  type ViewRule,
23
23
  type ViewRulePredicate,
@@ -210,28 +210,29 @@ export const fakeElements = {
210
210
 
211
211
  export type FakeElementIds = keyof typeof fakeElements
212
212
 
213
- const rel = ({
213
+ const rel = <Source extends FakeElementIds, Target extends FakeElementIds>({
214
214
  source,
215
215
  target,
216
216
  title,
217
217
  ...props
218
218
  }: {
219
- source: FakeElementIds
220
- target: FakeElementIds
219
+ source: Source
220
+ target: Target
221
221
  title?: string
222
222
  kind?: string
223
- color?: ThemeColor
223
+ color?: Color
224
224
  line?: RelationshipLineType
225
225
  head?: RelationshipArrowType
226
226
  tail?: RelationshipArrowType
227
227
  tags?: NonEmptyArray<TestTag>
228
- }): Relation => ({
229
- id: `${source}:${target}` as RelationID,
230
- title: title ?? '',
231
- source: source as Fqn,
232
- target: target as Fqn,
233
- ...(props as any)
234
- })
228
+ }) =>
229
+ ({
230
+ id: `${source}:${target}` as RelationID,
231
+ title: title ?? '',
232
+ source: source as Fqn,
233
+ target: target as Fqn,
234
+ ...(props as any)
235
+ }) as Omit<Relation, 'id'> & { id: `${Source}:${Target}` }
235
236
 
236
237
  export const fakeRelations = [
237
238
  rel({
@@ -321,7 +322,7 @@ export const fakeRelations = [
321
322
  })
322
323
  ]
323
324
 
324
- export type FakeRelationIds = keyof typeof fakeRelations
325
+ export type FakeRelationIds = (typeof fakeRelations)[number]['id']
325
326
 
326
327
  export const fakeModel = new LikeC4ModelGraph({
327
328
  elements: fakeElements,
@@ -335,6 +336,7 @@ const emptyView = {
335
336
  description: null,
336
337
  tags: null,
337
338
  links: null,
339
+ customColorDefinitions: {},
338
340
  rules: []
339
341
  }
340
342
 
@@ -370,7 +372,7 @@ export function $custom(
370
372
  description?: string
371
373
  technology?: string
372
374
  shape?: ElementShape
373
- color?: ThemeColor
375
+ color?: Color
374
376
  border?: BorderStyle
375
377
  icon?: string
376
378
  opacity?: number
@@ -1,4 +1,5 @@
1
1
  import type {
2
+ Color,
2
3
  ComputedEdge,
3
4
  ComputedElementView,
4
5
  EdgeId,
@@ -212,7 +213,7 @@ export class ComputeCtx {
212
213
  description?: string | undefined
213
214
  technology?: string | undefined
214
215
  kind?: RelationshipKind | undefined
215
- color?: ThemeColor | undefined
216
+ color?: Color | undefined
216
217
  line?: RelationshipLineType | undefined
217
218
  head?: RelationshipArrowType | undefined
218
219
  tail?: RelationshipArrowType | undefined
@@ -273,7 +274,7 @@ export class ComputeCtx {
273
274
  edge,
274
275
  this.getEdgeLabel(relation),
275
276
  isTruthy(relation.description) && { description: relation.description },
276
- isTruthy(relation.technology) && { description: relation.technology },
277
+ isTruthy(relation.technology) && { technology: relation.technology },
277
278
  isTruthy(relation.kind) && { kind: relation.kind },
278
279
  relation.color && { color: relation.color },
279
280
  relation.line && { line: relation.line },
@@ -537,16 +538,18 @@ export class ComputeCtx {
537
538
  return this
538
539
  }
539
540
  nonexhaustive(expr)
540
- }
541
+ }
541
542
 
542
- protected getEdgeLabel(relation: { title: String | undefined, technology?: String | undefined }): { label: String } | false {
543
+ protected getEdgeLabel(
544
+ relation: { title: String | undefined; technology?: String | undefined }
545
+ ): { label: String } | false {
543
546
  const labelParts: String[] = []
544
547
 
545
- if(isTruthy(relation.title)) {
548
+ if (isTruthy(relation.title)) {
546
549
  labelParts.push(relation.title)
547
550
  }
548
551
 
549
- if(isTruthy(relation.technology)) {
552
+ if (isTruthy(relation.technology)) {
550
553
  labelParts.push(`[${relation.technology}]`)
551
554
  }
552
555
 
@@ -306,15 +306,15 @@ function edgesIncomingExpr(this: ComputeCtx, expr: Expr.ElementExpression) {
306
306
  return this.graph.edgesBetween(sources, targets)
307
307
  }
308
308
 
309
- const filterEdges = (edges: ComputeCtx.Edge[], where?: RelationPredicateFn) => {
309
+ const filterEdges = (edges: ReadonlyArray<ComputeCtx.Edge>, where?: RelationPredicateFn) => {
310
310
  if (!where) {
311
- return edges
311
+ return edges as ComputeCtx.Edge[]
312
312
  }
313
313
  return pipe(
314
314
  edges,
315
315
  map(e => ({ ...e, relations: e.relations.filter(where) })),
316
316
  remedaFilter(e => e.relations.length > 0)
317
- )
317
+ ) as ComputeCtx.Edge[]
318
318
  }
319
319
 
320
320
  const filterRelations = (edges: ComputeCtx.Edge[], where?: RelationPredicateFn) => {
@@ -10,6 +10,7 @@ const emptyView = {
10
10
  description: null,
11
11
  tags: null,
12
12
  links: null,
13
+ customColorDefinitions: {},
13
14
  rules: []
14
15
  }
15
16
 
@@ -1,4 +1,5 @@
1
1
  import type {
2
+ Color,
2
3
  ComputedDynamicView,
3
4
  ComputedEdge,
4
5
  DynamicView,
@@ -38,7 +39,7 @@ export namespace DynamicViewComputeCtx {
38
39
  title: string | null
39
40
  description?: string
40
41
  technology?: string
41
- color?: ThemeColor
42
+ color?: Color
42
43
  line?: RelationshipLineType
43
44
  head?: RelationshipArrowType
44
45
  tail?: RelationshipArrowType
@@ -1,5 +1,5 @@
1
1
  import { Expr, nonexhaustive, parentFqn } from '@likec4/core'
2
- import { type Element, whereOperatorAsPredicate } from '@likec4/core/types'
2
+ import { type Element, whereOperatorAsPredicate } from '@likec4/core'
3
3
  import { isNullish } from 'remeda'
4
4
 
5
5
  type Predicate<T> = (x: T) => boolean
@@ -1,4 +1,3 @@
1
- import pkg from '@dagrejs/graphlib'
2
1
  import {
3
2
  compareByFqnHierarchically,
4
3
  compareRelations,
@@ -10,10 +9,7 @@ import {
10
9
  nonNullable
11
10
  } from '@likec4/core'
12
11
  import { difference, filter, map, pipe, sort, take } from 'remeda'
13
-
14
- // '@dagrejs/graphlib' is a CommonJS module
15
- // Here is a workaround to import it
16
- const { Graph, alg } = pkg
12
+ import { Graph, postorder } from '../../utils/graphlib'
17
13
 
18
14
  // side effect
19
15
  function sortChildren(nodes: readonly ComputedNode[]) {
@@ -92,7 +88,7 @@ export function sortNodes({
92
88
  map(n => n.id)
93
89
  )
94
90
  }
95
- const orderedIds = alg.postorder(g, sources).reverse() as Fqn[]
91
+ const orderedIds = postorder(g, sources).reverse() as Fqn[]
96
92
  const sorted = orderedIds.map(getNode)
97
93
  if (sorted.length < nodes.length) {
98
94
  const unsorted = difference(nodes, sorted)
package/src/module.ts CHANGED
@@ -9,7 +9,7 @@ import {
9
9
  type PartialLangiumSharedServices
10
10
  } from 'langium/lsp'
11
11
  import { LikeC4GeneratedModule, LikeC4GeneratedSharedModule } from './generated/module'
12
- import { logErrorToTelemetry } from './logger'
12
+ import { logErrorToTelemetry, logToLspConnection } from './logger'
13
13
  import {
14
14
  LikeC4CodeLensProvider,
15
15
  LikeC4CompletionProvider,
@@ -17,6 +17,7 @@ import {
17
17
  LikeC4DocumentLinkProvider,
18
18
  LikeC4DocumentSymbolProvider,
19
19
  LikeC4HoverProvider,
20
+ LikeC4RenameProvider,
20
21
  LikeC4SemanticTokenProvider
21
22
  } from './lsp'
22
23
  import { FqnIndex, LikeC4ModelBuilder, LikeC4ModelLocator, LikeC4ModelParser } from './model'
@@ -69,6 +70,7 @@ export interface LikeC4AddedServices {
69
70
  ModelChanges: LikeC4ModelChanges
70
71
  }
71
72
  lsp: {
73
+ RenameProvider: LikeC4RenameProvider
72
74
  CompletionProvider: LikeC4CompletionProvider
73
75
  DocumentHighlightProvider: LikeC4DocumentHighlightProvider
74
76
  DocumentSymbolProvider: LikeC4DocumentSymbolProvider
@@ -101,6 +103,7 @@ export const LikeC4Module: Module<LikeC4Services, PartialLangiumServices & LikeC
101
103
  ModelLocator: bind(LikeC4ModelLocator)
102
104
  },
103
105
  lsp: {
106
+ RenameProvider: bind(LikeC4RenameProvider),
104
107
  CompletionProvider: bind(LikeC4CompletionProvider),
105
108
  DocumentHighlightProvider: bind(LikeC4DocumentHighlightProvider),
106
109
  DocumentSymbolProvider: bind(LikeC4DocumentSymbolProvider),
@@ -136,7 +139,15 @@ export function createCustomLanguageServices<I1, I2, I3, I extends I1 & I2 & I3
136
139
  const likec4 = inject(modules)
137
140
  shared.ServiceRegistry.register(likec4)
138
141
  registerValidationChecks(likec4)
139
- likec4.Rpc.init()
142
+
143
+ if (!context.connection) {
144
+ // We don't run inside a language server
145
+ // Therefore, initialize the configuration provider instantly
146
+ shared.workspace.ConfigurationProvider.initialized({})
147
+ } else {
148
+ likec4.Rpc.init()
149
+ }
150
+
140
151
  return { shared, likec4 }
141
152
  }
142
153
 
@@ -146,6 +157,7 @@ export function createSharedServices(context: LanguageServicesContext = {}): Lik
146
157
  ...context
147
158
  }
148
159
  if (context.connection) {
160
+ logToLspConnection(context.connection)
149
161
  logErrorToTelemetry(context.connection)
150
162
  }
151
163
 
@@ -164,7 +176,15 @@ export function createLanguageServices(context: LanguageServicesContext = {}): {
164
176
  const likec4 = inject(createDefaultModule({ shared }), LikeC4GeneratedModule, LikeC4Module)
165
177
  shared.ServiceRegistry.register(likec4)
166
178
  registerValidationChecks(likec4)
167
- likec4.Rpc.init()
179
+
180
+ if (!context.connection) {
181
+ // We don't run inside a language server
182
+ // Therefore, initialize the configuration provider instantly
183
+ shared.workspace.ConfigurationProvider.initialized({})
184
+ } else {
185
+ likec4.Rpc.init()
186
+ }
187
+
168
188
  return { shared, likec4 }
169
189
  }
170
190
 
package/src/protocol.ts CHANGED
@@ -1,9 +1,8 @@
1
1
  import type {
2
- AutoLayoutDirection,
2
+ ComputedLikeC4Model,
3
3
  ComputedView,
4
4
  Fqn,
5
- LikeC4ComputedModel,
6
- LikeC4Model,
5
+ ParsedLikeC4Model,
7
6
  RelationID,
8
7
  ViewChange,
9
8
  ViewID
@@ -17,12 +16,12 @@ export type OnDidChangeModelNotification = typeof onDidChangeModel
17
16
  // #endregion
18
17
 
19
18
  // #region To server
20
- export const fetchModel = new RequestType0<{ model: LikeC4Model | null }, void>(
19
+ export const fetchModel = new RequestType0<{ model: ParsedLikeC4Model | null }, void>(
21
20
  'likec4/fetchModel'
22
21
  )
23
22
  export type FetchModelRequest = typeof fetchModel
24
23
 
25
- export const fetchComputedModel = new RequestType0<{ model: LikeC4ComputedModel | null }, void>(
24
+ export const fetchComputedModel = new RequestType0<{ model: ComputedLikeC4Model | null }, void>(
26
25
  'likec4/fetchComputedModel'
27
26
  )
28
27
  export type FetchComputedModelRequest = typeof fetchComputedModel
@@ -106,7 +106,8 @@ export class LikeC4ScopeComputation extends DefaultScopeComputation {
106
106
  const spec of specifications.flatMap(s => [
107
107
  ...s.elements,
108
108
  ...s.relationships,
109
- ...s.tags
109
+ ...s.tags,
110
+ ...s.colors
110
111
  ])
111
112
  ) {
112
113
  try {
@@ -136,6 +137,14 @@ export class LikeC4ScopeComputation extends DefaultScopeComputation {
136
137
  }
137
138
  continue
138
139
  }
140
+ case ast.isSpecificationColor(spec): {
141
+ if (isTruthy(spec.name.name)) {
142
+ docExports.push(
143
+ this.descriptions.createDescription(spec.name, spec.name.name, document)
144
+ )
145
+ }
146
+ continue
147
+ }
139
148
  // Thow error if not exhaustive
140
149
  default:
141
150
  nonexhaustive(spec)
@@ -1,4 +1,5 @@
1
- import type { likec4 as c4 } from '@likec4/core'
1
+ import { invariant } from '@likec4/core'
2
+ import type * as c4 from '@likec4/core'
2
3
  import type { AstNode } from 'langium'
3
4
  import {
4
5
  type AstNodeDescription,
@@ -7,6 +8,7 @@ import {
7
8
  DONE_RESULT,
8
9
  EMPTY_SCOPE,
9
10
  EMPTY_STREAM,
11
+ MapScope,
10
12
  type ReferenceInfo,
11
13
  type Scope,
12
14
  type Stream,
@@ -102,6 +104,17 @@ export class LikeC4ScopeProvider extends DefaultScopeProvider {
102
104
  if (parent) {
103
105
  return new StreamScope(this.scopeElementRef(parent))
104
106
  }
107
+ // if we have elementRef "this" or "it" we resolve it to the closest element
108
+ if (context.reference.$refText === 'this' || context.reference.$refText === 'it') {
109
+ const closestElement = AstUtils.getContainerOfType(container, ast.isElement)
110
+ if (closestElement) {
111
+ return new MapScope([
112
+ this.descriptions.createDescription(closestElement, context.reference.$refText)
113
+ ])
114
+ } else {
115
+ return EMPTY_SCOPE
116
+ }
117
+ }
105
118
  }
106
119
  return this.computeScope(context)
107
120
  } catch (e) {
@@ -116,26 +129,26 @@ export class LikeC4ScopeProvider extends DefaultScopeProvider {
116
129
 
117
130
  protected computeScope(context: ReferenceInfo) {
118
131
  const referenceType = this.reflection.getReferenceType(context)
132
+ // computeScope is called only for elements
133
+ invariant(referenceType === ast.Element, 'Invalid reference type')
119
134
  const scopes: Stream<AstNodeDescription>[] = []
120
135
  const doc = getDocument(context.container)
121
136
  const precomputed = doc.precomputedScopes
122
137
 
123
138
  if (precomputed) {
124
139
  const byReferenceType = (desc: AstNodeDescription) => this.reflection.isSubtype(desc.type, referenceType)
125
-
126
140
  let container: AstNode | undefined = context.container
127
141
  while (container) {
128
142
  const elements = precomputed.get(container).filter(byReferenceType)
129
143
  if (elements.length > 0) {
130
144
  scopes.push(stream(elements))
131
145
  }
132
- if (referenceType === ast.Element) {
133
- if (ast.isExtendElementBody(container)) {
134
- scopes.push(this.scopeExtendElement(container.$container))
135
- }
136
- if (ast.isElementViewBody(container)) {
137
- scopes.push(this.scopeElementView(container.$container))
138
- }
146
+
147
+ if (ast.isExtendElementBody(container)) {
148
+ scopes.push(this.scopeExtendElement(container.$container))
149
+ }
150
+ if (ast.isElementViewBody(container)) {
151
+ scopes.push(this.scopeElementView(container.$container))
139
152
  }
140
153
  container = container.$container
141
154
  }