@likec4/language-server 1.4.0 → 1.6.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 (45) hide show
  1. package/README.md +1 -1
  2. package/contrib/likec4.tmLanguage.json +1 -1
  3. package/package.json +26 -14
  4. package/src/Rpc.ts +25 -2
  5. package/src/ast.ts +19 -15
  6. package/src/generated/ast.ts +390 -203
  7. package/src/generated/grammar.ts +1 -1
  8. package/src/generated-lib/icons.ts +952 -0
  9. package/src/like-c4.langium +120 -64
  10. package/src/likec4lib.ts +7 -0
  11. package/src/lsp/DocumentSymbolProvider.ts +28 -1
  12. package/src/lsp/SemanticTokenProvider.ts +41 -22
  13. package/src/model/fqn-computation.ts +29 -7
  14. package/src/model/fqn-index.ts +18 -31
  15. package/src/model/model-builder.ts +13 -9
  16. package/src/model/model-locator.ts +7 -7
  17. package/src/model/model-parser.ts +166 -69
  18. package/src/model-change/changeElementStyle.ts +6 -6
  19. package/src/model-graph/compute-view/__test__/fixture.ts +52 -24
  20. package/src/model-graph/compute-view/compute.ts +51 -20
  21. package/src/model-graph/compute-view/predicates.ts +6 -1
  22. package/src/model-graph/dynamic-view/__test__/fixture.ts +2 -2
  23. package/src/model-graph/dynamic-view/compute.ts +2 -2
  24. package/src/model-graph/utils/{applyElementCustomProperties.ts → applyCustomElementProperties.ts} +5 -3
  25. package/src/model-graph/utils/applyCustomRelationProperties.ts +50 -0
  26. package/src/model-graph/utils/applyViewRuleStyles.ts +11 -34
  27. package/src/model-graph/utils/elementExpressionToPredicate.ts +32 -0
  28. package/src/references/scope-computation.ts +113 -60
  29. package/src/references/scope-provider.ts +3 -23
  30. package/src/shared/NodeKindProvider.ts +1 -0
  31. package/src/shared/WorkspaceManager.ts +15 -6
  32. package/src/validation/dynamic-view-rule.ts +19 -26
  33. package/src/validation/element.ts +8 -4
  34. package/src/validation/index.ts +9 -6
  35. package/src/validation/property-checks.ts +23 -1
  36. package/src/validation/view-predicates/custom-element-expr.ts +21 -8
  37. package/src/validation/view-predicates/custom-relation-expr.ts +16 -0
  38. package/src/validation/view-predicates/expanded-element.ts +13 -24
  39. package/src/validation/view-predicates/incoming.ts +5 -5
  40. package/src/validation/view-predicates/index.ts +1 -0
  41. package/src/validation/view-predicates/outgoing.ts +5 -5
  42. package/src/view-utils/assignNavigateTo.ts +2 -2
  43. package/src/view-utils/manual-layout.ts +4 -2
  44. package/src/view-utils/resolve-extended-views.ts +2 -2
  45. package/src/view-utils/resolve-relative-paths.ts +3 -3
package/README.md CHANGED
@@ -1,5 +1,5 @@
1
1
  # `@likec4/language-server`
2
2
 
3
- [docs](https://docs.likec4.dev/) | [playground](https://playground.likec4.dev/) | [demo](https://template.likec4.dev/view/cloud)
3
+ [docs](https://likec4.dev/) | [playground](https://playground.likec4.dev/) | [demo](https://template.likec4.dev/view/cloud)
4
4
 
5
5
  Language Server Protocol (LSP) based on [languim](https://github.com/languim/languim) library.
@@ -12,7 +12,7 @@
12
12
  },
13
13
  {
14
14
  "name": "keyword.control.likec4",
15
- "match": "\\b(BottomTop|LeftRight|RightLeft|TopBottom|amber|autoLayout|blue|border|browser|color|crow|cylinder|dashed|description|diamond|dotted|dynamic|element|exclude|extend|extends|gray|green|head|icon|include|indigo|it|kind|line|link|mobile|model|muted|navigateTo|none|normal|odiamond|of|onormal|opacity|open|person|primary|queue|rectangle|red|relationship|secondary|shape|sky|slate|solid|specification|storage|style|tag|tail|technology|this|title|vee|view|views|with)\\b"
15
+ "match": "\\b(BottomTop|LeftRight|RightLeft|TopBottom|amber|autoLayout|blue|border|browser|color|crow|cylinder|dashed|description|diamond|dot|dotted|dynamic|element|element\\.kind|element\\.tag|exclude|extend|extends|gray|green|head|icon|icons|include|indigo|it|likec4lib|line|link|mobile|model|muted|navigateTo|none|normal|odiamond|odot|of|onormal|opacity|open|person|primary|queue|rectangle|red|relationship|secondary|shape|sky|slate|solid|specification|storage|style|tag|tail|technology|this|title|vee|view|views|with)\\b"
16
16
  },
17
17
  {
18
18
  "name": "string.quoted.double.likec4",
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@likec4/language-server",
3
3
  "description": "LikeC4 Language Server",
4
- "version": "1.4.0",
4
+ "version": "1.6.0",
5
5
  "license": "MIT",
6
6
  "bugs": "https://github.com/likec4/likec4/issues",
7
7
  "homepage": "https://likec4.dev",
@@ -26,6 +26,10 @@
26
26
  "types": "./dist/index.d.ts",
27
27
  "default": "./dist/index.js"
28
28
  },
29
+ "./likec4lib": {
30
+ "types": "./dist/likec4lib.d.ts",
31
+ "default": "./dist/likec4lib.js"
32
+ },
29
33
  "./browser": {
30
34
  "types": "./dist/browser/index.d.ts",
31
35
  "default": "./dist/browser/index.js"
@@ -51,6 +55,10 @@
51
55
  "types": "./dist/index.d.ts",
52
56
  "default": "./dist/index.js"
53
57
  },
58
+ "./likec4lib": {
59
+ "types": "./dist/likec4lib.d.ts",
60
+ "default": "./dist/likec4lib.js"
61
+ },
54
62
  "./browser": {
55
63
  "types": "./dist/browser/index.d.ts",
56
64
  "default": "./dist/browser/index.js"
@@ -71,45 +79,49 @@
71
79
  },
72
80
  "scripts": {
73
81
  "typecheck": "tsc --noEmit",
82
+ "pregenerate": "rm -f src/generated/*",
74
83
  "watch:langium": "langium generate --watch",
75
84
  "watch:ts": "tsc --watch",
76
- "generate": "langium generate",
85
+ "generate": "langium generate && tsx scripts/generate-icons.ts",
77
86
  "dev": "run-p 'watch:*'",
78
87
  "lint": "run -T eslint src/ --fix",
79
88
  "clean": "run -T rimraf dist contrib",
80
89
  "test": "vitest run --no-isolate",
90
+ "vitest:ui": "vitest --no-isolate --ui",
81
91
  "test:watch": "vitest"
82
92
  },
83
93
  "dependencies": {
84
94
  "@dagrejs/graphlib": "^2.2.2",
85
- "@likec4/core": "1.4.0",
95
+ "@likec4/core": "1.6.0",
86
96
  "@total-typescript/ts-reset": "^0.5.1",
87
97
  "fast-equals": "^5.0.1",
88
98
  "indent-string": "^5.0.0",
89
99
  "json5": "^2.2.3",
90
- "langium": "3.1.0",
100
+ "langium": "3.1.2",
91
101
  "object-hash": "^3.0.0",
92
102
  "p-debounce": "^4.0.0",
93
- "rambdax": "^9.1.1",
94
- "remeda": "^1.61.0",
103
+ "remeda": "^2.3.0",
95
104
  "string-hash": "^1.1.3",
96
105
  "strip-indent": "^4.0.0",
97
- "type-fest": "^4.18.2",
106
+ "type-fest": "^4.21.0",
98
107
  "ufo": "^1.5.3",
99
108
  "vscode-languageserver": "9.0.1",
100
109
  "vscode-languageserver-protocol": "3.17.5",
101
110
  "vscode-uri": "3.0.8"
102
111
  },
103
112
  "devDependencies": {
104
- "@likec4/tsconfig": "1.4.0",
105
- "@types/node": "^20.14.2",
113
+ "@likec4/icons": "1.6.0",
114
+ "@likec4/tsconfig": "1.6.0",
115
+ "@types/node": "^20.14.10",
106
116
  "@types/object-hash": "^3.0.6",
107
117
  "@types/string-hash": "^1.1.3",
108
- "execa": "^9.1.0",
118
+ "execa": "^9.3.0",
119
+ "glob": "^11.0.0",
109
120
  "langium-cli": "3.1.0",
110
- "npm-run-all2": "^6.1.2",
111
- "typescript": "^5.4.5",
112
- "vitest": "~1.5.3"
121
+ "npm-run-all2": "^6.2.2",
122
+ "tsx": "~4.9.3",
123
+ "typescript": "^5.5.3",
124
+ "vitest": "~2.0.3"
113
125
  },
114
- "packageManager": "yarn@4.3.0"
126
+ "packageManager": "yarn@4.3.1"
115
127
  }
package/src/Rpc.ts CHANGED
@@ -3,8 +3,9 @@ import { logError, logger } from './logger'
3
3
  import type { LikeC4Services } from './module'
4
4
 
5
5
  import { nonexhaustive } from '@likec4/core'
6
- import { Disposable, URI, UriUtils } from 'langium'
6
+ import { Disposable, interruptAndCheck, URI, UriUtils } from 'langium'
7
7
  import { isLikeC4LangiumDocument } from './ast'
8
+ import { Scheme } from './likec4lib'
8
9
  import {
9
10
  buildDocuments,
10
11
  changeView,
@@ -46,6 +47,8 @@ export class Rpc implements Disposable {
46
47
  }
47
48
  )
48
49
 
50
+ let isFirstBuild = true
51
+
49
52
  this.disposables.push(
50
53
  Disposable.create(() => {
51
54
  notifyModelParsed.cancel()
@@ -67,7 +70,7 @@ export class Rpc implements Disposable {
67
70
  const changed = docs.map(d => URI.parse(d))
68
71
  const notChanged = (uri: URI) => changed.every(c => !UriUtils.equals(c, uri))
69
72
  const deleted = LangiumDocuments.all
70
- .filter(d => isLikeC4LangiumDocument(d) && notChanged(d.uri))
73
+ .filter(d => isLikeC4LangiumDocument(d) && notChanged(d.uri) && d.uri.scheme !== Scheme)
71
74
  .map(d => d.uri)
72
75
  .toArray()
73
76
  logger.debug(
@@ -75,6 +78,26 @@ export class Rpc implements Disposable {
75
78
  changed (total ${changed.length}):${docs.map(d => '\n - ' + d).join('')}
76
79
  deleted (total ${deleted.length}):${deleted.map(d => '\n - ' + d.toString()).join('\n')}`
77
80
  )
81
+
82
+ if (!isFirstBuild && (changed.length + deleted.length) > 0) {
83
+ await Promise.allSettled(
84
+ [...changed, ...deleted].map(async d => {
85
+ const uri = d.toString()
86
+ logger.debug(`clear diagnostics for ${uri}`)
87
+ try {
88
+ await connection.sendDiagnostics({
89
+ uri,
90
+ diagnostics: []
91
+ })
92
+ } catch (e) {
93
+ // Ignore
94
+ logger.warn(`error clearing diagnostics for ${uri}: ${e}`)
95
+ }
96
+ })
97
+ )
98
+ await interruptAndCheck(cancelToken)
99
+ }
100
+ isFirstBuild = false
78
101
  await DocumentBuilder.update(changed, deleted, cancelToken)
79
102
  }),
80
103
  connection.onRequest(locate, params => {
package/src/ast.ts CHANGED
@@ -6,9 +6,9 @@ import {
6
6
  nonexhaustive,
7
7
  RelationRefError
8
8
  } from '@likec4/core'
9
- import type { AstNode, DiagnosticInfo, LangiumDocument, MultiMap } from 'langium'
9
+ import type { AstNode, AstNodeDescription, DiagnosticInfo, LangiumDocument, MultiMap } from 'langium'
10
10
  import { AstUtils, DocumentState } from 'langium'
11
- import { clamp, isNullish } from 'remeda'
11
+ import { clamp, isNullish, isTruthy } from 'remeda'
12
12
  import type { ConditionalPick, SetRequired, ValueOf } from 'type-fest'
13
13
  import type { Diagnostic } from 'vscode-languageserver-protocol'
14
14
  import { DiagnosticSeverity } from 'vscode-languageserver-protocol'
@@ -133,10 +133,8 @@ export const ElementOps = {
133
133
  }
134
134
  }
135
135
 
136
- export interface DocFqnIndexEntry {
137
- name: string
138
- el: WeakRef<ast.Element>
139
- path: string
136
+ export interface DocFqnIndexAstNodeDescription extends AstNodeDescription {
137
+ fqn: c4.Fqn
140
138
  }
141
139
 
142
140
  // export type LikeC4AstNode = ast.LikeC4AstType[keyof ast.LikeC4AstType]
@@ -150,14 +148,14 @@ export interface LikeC4DocumentProps {
150
148
  c4Relations?: ParsedAstRelation[]
151
149
  c4Views?: ParsedAstView[]
152
150
  // Fqn -> Element
153
- c4fqns?: MultiMap<c4.Fqn, DocFqnIndexEntry>
151
+ c4fqnIndex?: MultiMap<c4.Fqn, DocFqnIndexAstNodeDescription>
154
152
  }
155
153
 
156
154
  export interface LikeC4LangiumDocument
157
155
  extends Omit<LangiumDocument<LikeC4Grammar>, 'diagnostics'>, LikeC4DocumentProps
158
156
  {}
159
157
  export interface FqnIndexedDocument
160
- extends Omit<LangiumDocument<LikeC4Grammar>, 'diagnostics'>, SetRequired<LikeC4DocumentProps, 'c4fqns'>
158
+ extends Omit<LangiumDocument<LikeC4Grammar>, 'diagnostics'>, SetRequired<LikeC4DocumentProps, 'c4fqnIndex'>
161
159
  {}
162
160
 
163
161
  // export type ParsedLikeC4LangiumDocument = SetRequired<FqnIndexedDocument, keyof LikeC4DocumentProps>
@@ -166,7 +164,7 @@ export interface ParsedLikeC4LangiumDocument
166
164
  {}
167
165
 
168
166
  export function cleanParsedModel(doc: LikeC4LangiumDocument) {
169
- const props: Required<Omit<LikeC4DocumentProps, 'c4fqns' | 'diagnostics'>> = {
167
+ const props: Required<Omit<LikeC4DocumentProps, 'c4fqnIndex' | 'diagnostics'>> = {
170
168
  c4Specification: {
171
169
  kinds: {},
172
170
  relationships: {}
@@ -179,7 +177,7 @@ export function cleanParsedModel(doc: LikeC4LangiumDocument) {
179
177
  }
180
178
 
181
179
  export function isFqnIndexedDocument(doc: LangiumDocument): doc is FqnIndexedDocument {
182
- return isLikeC4LangiumDocument(doc) && doc.state >= DocumentState.IndexedContent && !!doc.c4fqns
180
+ return isLikeC4LangiumDocument(doc) && doc.state >= DocumentState.IndexedContent && !!doc.c4fqnIndex
183
181
  }
184
182
 
185
183
  export function isLikeC4LangiumDocument(doc: LangiumDocument): doc is LikeC4LangiumDocument {
@@ -196,7 +194,7 @@ export function isParsedLikeC4LangiumDocument(
196
194
  && !!doc.c4Elements
197
195
  && !!doc.c4Relations
198
196
  && !!doc.c4Views
199
- && !!doc.c4fqns
197
+ && !!doc.c4fqnIndex
200
198
  )
201
199
  }
202
200
 
@@ -209,15 +207,18 @@ function validatableAstNodeGuards<const Predicates extends Guard<AstNode>[]>(
209
207
  return (n: AstNode): n is Guarded<Predicates[number]> => predicates.some(p => p(n))
210
208
  }
211
209
  const isValidatableAstNode = validatableAstNodeGuards([
212
- ast.isCustomElementExprBody,
213
- ast.isViewRulePredicateExpr,
210
+ ast.isDynamicViewRulePredicateIterator,
211
+ ast.isCustomElementExpression,
212
+ ast.isCustomRelationExpression,
213
+ ast.isElementExpression,
214
+ ast.isRelationExpression,
214
215
  ast.isDynamicViewRulePredicate,
216
+ ast.isDynamicViewStep,
215
217
  ast.isViewProperty,
216
218
  ast.isStyleProperty,
217
219
  ast.isTags,
218
220
  ast.isViewRule,
219
221
  ast.isDynamicViewRule,
220
- ast.isDynamicViewStep,
221
222
  ast.isElementViewBody,
222
223
  ast.isDynamicViewBody,
223
224
  ast.isLikeC4View,
@@ -337,7 +338,10 @@ export function toElementStyle(props?: Array<ast.StyleProperty>) {
337
338
  break
338
339
  }
339
340
  case ast.isIconProperty(prop): {
340
- result.icon = prop.value as c4.IconUrl
341
+ const icon = prop.libicon?.ref?.name ?? prop.value
342
+ if (isTruthy(icon)) {
343
+ result.icon = icon as c4.IconUrl
344
+ }
341
345
  break
342
346
  }
343
347
  case ast.isOpacityProperty(prop): {