@likec4/language-server 1.18.0 → 1.19.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 (250) hide show
  1. package/dist/LikeC4FileSystem.d.ts +13 -0
  2. package/dist/LikeC4FileSystem.js +27 -0
  3. package/dist/Rpc.d.ts +9 -0
  4. package/dist/Rpc.js +132 -0
  5. package/dist/ast.d.ts +200 -0
  6. package/dist/ast.js +276 -0
  7. package/dist/browser.d.ts +7 -20
  8. package/dist/browser.js +13 -0
  9. package/dist/documentation/documentation-provider.d.ts +8 -0
  10. package/dist/documentation/documentation-provider.js +46 -0
  11. package/dist/documentation/index.d.ts +1 -0
  12. package/dist/documentation/index.js +1 -0
  13. package/dist/formatting/LikeC4Formatter.d.ts +27 -0
  14. package/dist/formatting/LikeC4Formatter.js +261 -0
  15. package/dist/formatting/utils.d.ts +6 -0
  16. package/dist/formatting/utils.js +15 -0
  17. package/dist/generated/ast.d.ts +1242 -0
  18. package/dist/generated/ast.js +1945 -0
  19. package/dist/generated/grammar.d.ts +6 -0
  20. package/dist/generated/grammar.js +3 -0
  21. package/dist/generated/module.d.ts +9 -0
  22. package/dist/generated/module.js +23 -0
  23. package/dist/generated-lib/icons.d.ts +1 -0
  24. package/dist/{likec4lib.mjs → generated-lib/icons.js} +1 -6
  25. package/dist/index.d.ts +9 -31
  26. package/dist/index.js +14 -0
  27. package/dist/like-c4.langium +845 -0
  28. package/dist/likec4lib.d.ts +4 -6
  29. package/dist/likec4lib.js +4 -0
  30. package/dist/logger.d.ts +7 -0
  31. package/dist/logger.js +73 -0
  32. package/dist/lsp/CodeLensProvider.d.ts +9 -0
  33. package/dist/lsp/CodeLensProvider.js +40 -0
  34. package/dist/lsp/CompletionProvider.d.ts +6 -0
  35. package/dist/lsp/CompletionProvider.js +135 -0
  36. package/dist/lsp/DocumentHighlightProvider.d.ts +9 -0
  37. package/dist/lsp/DocumentHighlightProvider.js +10 -0
  38. package/dist/lsp/DocumentLinkProvider.d.ts +11 -0
  39. package/dist/lsp/DocumentLinkProvider.js +49 -0
  40. package/dist/lsp/DocumentSymbolProvider.d.ts +32 -0
  41. package/dist/lsp/DocumentSymbolProvider.js +274 -0
  42. package/dist/lsp/HoverProvider.d.ts +10 -0
  43. package/dist/lsp/HoverProvider.js +69 -0
  44. package/dist/lsp/RenameProvider.d.ts +5 -0
  45. package/dist/lsp/RenameProvider.js +6 -0
  46. package/dist/lsp/SemanticTokenProvider.d.ts +7 -0
  47. package/dist/lsp/SemanticTokenProvider.js +297 -0
  48. package/dist/lsp/index.d.ts +7 -0
  49. package/dist/lsp/index.js +7 -0
  50. package/dist/model/deployments-index.d.ts +60 -0
  51. package/dist/model/deployments-index.js +181 -0
  52. package/dist/model/fqn-computation.d.ts +3 -0
  53. package/dist/model/fqn-computation.js +72 -0
  54. package/dist/model/fqn-index.d.ts +25 -0
  55. package/dist/model/fqn-index.js +96 -0
  56. package/dist/model/index.d.ts +6 -0
  57. package/dist/model/index.js +6 -0
  58. package/dist/model/model-builder.d.ts +32 -0
  59. package/dist/model/model-builder.js +598 -0
  60. package/dist/model/model-locator.d.ts +23 -0
  61. package/dist/model/model-locator.js +126 -0
  62. package/dist/model/model-parser-where.d.ts +3 -0
  63. package/dist/model/model-parser-where.js +70 -0
  64. package/dist/model/model-parser.d.ts +292 -0
  65. package/dist/model/model-parser.js +72 -0
  66. package/dist/model/parser/Base.d.ts +28 -0
  67. package/dist/model/parser/Base.js +87 -0
  68. package/dist/model/parser/DeploymentModelParser.d.ts +33 -0
  69. package/dist/model/parser/DeploymentModelParser.js +162 -0
  70. package/dist/model/parser/DeploymentViewParser.d.ts +38 -0
  71. package/dist/model/parser/DeploymentViewParser.js +98 -0
  72. package/dist/model/parser/FqnRefParser.d.ts +29 -0
  73. package/dist/model/parser/FqnRefParser.js +108 -0
  74. package/dist/model/parser/GlobalsParser.d.ts +66 -0
  75. package/dist/model/parser/GlobalsParser.js +80 -0
  76. package/dist/model/parser/ModelParser.d.ts +27 -0
  77. package/dist/model/parser/ModelParser.js +122 -0
  78. package/dist/model/parser/PredicatesParser.d.ts +34 -0
  79. package/dist/model/parser/PredicatesParser.js +272 -0
  80. package/dist/model/parser/SpecificationParser.d.ts +27 -0
  81. package/dist/model/parser/SpecificationParser.js +120 -0
  82. package/dist/model/parser/ViewsParser.d.ts +64 -0
  83. package/dist/model/parser/ViewsParser.js +377 -0
  84. package/dist/model-change/ModelChanges.d.ts +15 -0
  85. package/dist/model-change/ModelChanges.js +89 -0
  86. package/dist/model-change/changeElementStyle.d.ts +16 -0
  87. package/dist/model-change/changeElementStyle.js +136 -0
  88. package/dist/model-change/changeViewLayout.d.ts +12 -0
  89. package/dist/model-change/changeViewLayout.js +32 -0
  90. package/dist/model-change/saveManualLayout.d.ts +11 -0
  91. package/dist/model-change/saveManualLayout.js +27 -0
  92. package/dist/module.d.ts +70 -0
  93. package/dist/module.js +162 -0
  94. package/dist/protocol.d.ts +38 -23
  95. package/dist/protocol.js +15 -0
  96. package/dist/references/index.d.ts +3 -0
  97. package/dist/references/index.js +3 -0
  98. package/dist/references/name-provider.d.ts +9 -0
  99. package/dist/references/name-provider.js +33 -0
  100. package/dist/references/scope-computation.d.ts +20 -0
  101. package/dist/references/scope-computation.js +281 -0
  102. package/dist/references/scope-provider.d.ts +16 -0
  103. package/dist/references/scope-provider.js +165 -0
  104. package/dist/shared/NodeKindProvider.d.ts +15 -0
  105. package/dist/shared/NodeKindProvider.js +108 -0
  106. package/dist/shared/WorkspaceManager.d.ts +18 -0
  107. package/dist/shared/WorkspaceManager.js +36 -0
  108. package/dist/shared/WorkspaceSymbolProvider.d.ts +3 -0
  109. package/dist/shared/WorkspaceSymbolProvider.js +3 -0
  110. package/dist/shared/index.d.ts +3 -0
  111. package/dist/shared/index.js +3 -0
  112. package/dist/test/index.d.ts +1 -0
  113. package/dist/test/index.js +1 -0
  114. package/dist/test/setup.d.ts +1 -0
  115. package/dist/test/setup.js +7 -0
  116. package/dist/test/testServices.d.ts +22 -0
  117. package/dist/test/testServices.js +119 -0
  118. package/dist/utils/elementRef.d.ts +11 -0
  119. package/dist/utils/elementRef.js +15 -0
  120. package/dist/utils/fqnRef.d.ts +8 -0
  121. package/dist/utils/fqnRef.js +46 -0
  122. package/dist/utils/index.d.ts +1 -0
  123. package/dist/utils/index.js +1 -0
  124. package/dist/utils/printDocs.d.ts +2 -0
  125. package/dist/utils/printDocs.js +1 -0
  126. package/dist/utils/stringHash.d.ts +1 -0
  127. package/dist/utils/stringHash.js +5 -0
  128. package/dist/validation/_shared.d.ts +3 -0
  129. package/dist/validation/_shared.js +22 -0
  130. package/dist/validation/deployment-checks.d.ts +6 -0
  131. package/dist/validation/deployment-checks.js +114 -0
  132. package/dist/validation/dynamic-view-rule.d.ts +4 -0
  133. package/dist/validation/dynamic-view-rule.js +17 -0
  134. package/dist/validation/dynamic-view-step.d.ts +4 -0
  135. package/dist/validation/dynamic-view-step.js +29 -0
  136. package/dist/validation/element.d.ts +4 -0
  137. package/dist/validation/element.js +49 -0
  138. package/dist/validation/index.d.ts +15 -0
  139. package/dist/validation/index.js +152 -0
  140. package/dist/validation/property-checks.d.ts +6 -0
  141. package/dist/validation/property-checks.js +39 -0
  142. package/dist/validation/relation.d.ts +5 -0
  143. package/dist/validation/relation.js +56 -0
  144. package/dist/validation/specification.d.ts +11 -0
  145. package/dist/validation/specification.js +136 -0
  146. package/dist/validation/view-predicates/element-with.d.ts +4 -0
  147. package/dist/validation/view-predicates/element-with.js +31 -0
  148. package/dist/validation/view-predicates/expanded-element.d.ts +4 -0
  149. package/dist/validation/view-predicates/expanded-element.js +12 -0
  150. package/dist/validation/view-predicates/expression-v2.d.ts +5 -0
  151. package/dist/validation/view-predicates/expression-v2.js +83 -0
  152. package/dist/validation/view-predicates/incoming.d.ts +4 -0
  153. package/dist/validation/view-predicates/incoming.js +16 -0
  154. package/dist/validation/view-predicates/index.d.ts +6 -0
  155. package/dist/validation/view-predicates/index.js +6 -0
  156. package/dist/validation/view-predicates/outgoing.d.ts +4 -0
  157. package/dist/validation/view-predicates/outgoing.js +16 -0
  158. package/dist/validation/view-predicates/relation-with.d.ts +4 -0
  159. package/dist/validation/view-predicates/relation-with.js +13 -0
  160. package/dist/validation/view.d.ts +4 -0
  161. package/dist/validation/view.js +23 -0
  162. package/dist/view-utils/assignNavigateTo.d.ts +2 -0
  163. package/dist/view-utils/assignNavigateTo.js +25 -0
  164. package/dist/view-utils/index.d.ts +2 -0
  165. package/dist/view-utils/index.js +2 -0
  166. package/dist/view-utils/manual-layout.d.ts +7 -0
  167. package/dist/view-utils/manual-layout.js +99 -0
  168. package/dist/view-utils/resolve-relative-paths.d.ts +2 -0
  169. package/dist/view-utils/resolve-relative-paths.js +78 -0
  170. package/dist/views/configurable-layouter.d.ts +7 -0
  171. package/dist/views/configurable-layouter.js +55 -0
  172. package/dist/views/index.d.ts +1 -0
  173. package/dist/views/index.js +1 -0
  174. package/dist/views/likec4-views.d.ts +26 -0
  175. package/dist/views/likec4-views.js +113 -0
  176. package/package.json +40 -54
  177. package/src/LikeC4FileSystem.ts +22 -21
  178. package/src/Rpc.ts +13 -7
  179. package/src/ast.ts +44 -133
  180. package/src/browser.ts +11 -11
  181. package/src/documentation/documentation-provider.ts +52 -0
  182. package/src/documentation/index.ts +1 -0
  183. package/src/generated/ast.ts +177 -177
  184. package/src/generated/grammar.ts +1 -1
  185. package/src/index.ts +13 -9
  186. package/src/like-c4.langium +37 -34
  187. package/src/logger.ts +34 -55
  188. package/src/lsp/CompletionProvider.ts +4 -4
  189. package/src/lsp/DocumentSymbolProvider.ts +110 -28
  190. package/src/lsp/HoverProvider.ts +5 -3
  191. package/src/lsp/SemanticTokenProvider.ts +2 -2
  192. package/src/model/deployments-index.ts +18 -14
  193. package/src/model/fqn-computation.ts +8 -8
  194. package/src/model/model-builder.ts +62 -60
  195. package/src/model/model-parser.ts +62 -1574
  196. package/src/model/parser/Base.ts +107 -0
  197. package/src/model/parser/DeploymentModelParser.ts +192 -0
  198. package/src/model/parser/DeploymentViewParser.ts +116 -0
  199. package/src/model/parser/FqnRefParser.ts +118 -0
  200. package/src/model/parser/GlobalsParser.ts +96 -0
  201. package/src/model/parser/ModelParser.ts +141 -0
  202. package/src/model/parser/PredicatesParser.ts +291 -0
  203. package/src/model/parser/SpecificationParser.ts +133 -0
  204. package/src/model/parser/ViewsParser.ts +428 -0
  205. package/src/module.ts +71 -25
  206. package/src/protocol.ts +29 -4
  207. package/src/references/scope-computation.ts +35 -35
  208. package/src/references/scope-provider.ts +13 -7
  209. package/src/utils/{deploymentRef.ts → fqnRef.ts} +27 -2
  210. package/src/validation/_shared.ts +0 -1
  211. package/src/validation/deployment-checks.ts +49 -62
  212. package/src/validation/dynamic-view-rule.ts +5 -4
  213. package/src/validation/dynamic-view-step.ts +23 -26
  214. package/src/validation/index.ts +100 -9
  215. package/src/validation/property-checks.ts +11 -10
  216. package/src/validation/specification.ts +38 -38
  217. package/src/validation/view-predicates/element-with.ts +6 -5
  218. package/src/validation/view-predicates/expanded-element.ts +6 -5
  219. package/src/validation/view-predicates/expression-v2.ts +101 -0
  220. package/src/validation/view-predicates/incoming.ts +6 -5
  221. package/src/validation/view-predicates/index.ts +1 -1
  222. package/src/validation/view-predicates/outgoing.ts +6 -5
  223. package/src/validation/view-predicates/relation-with.ts +6 -5
  224. package/src/validation/view.ts +5 -5
  225. package/src/view-utils/assignNavigateTo.ts +1 -1
  226. package/src/view-utils/manual-layout.ts +25 -0
  227. package/src/views/configurable-layouter.ts +65 -0
  228. package/src/views/index.ts +1 -0
  229. package/src/views/likec4-views.ts +139 -0
  230. package/dist/browser.cjs +0 -25
  231. package/dist/browser.d.cts +0 -23
  232. package/dist/browser.d.mts +0 -23
  233. package/dist/browser.mjs +0 -20
  234. package/dist/index.cjs +0 -53
  235. package/dist/index.d.cts +0 -34
  236. package/dist/index.d.mts +0 -34
  237. package/dist/index.mjs +0 -46
  238. package/dist/likec4lib.cjs +0 -1546
  239. package/dist/likec4lib.d.cts +0 -6
  240. package/dist/likec4lib.d.mts +0 -6
  241. package/dist/protocol.cjs +0 -25
  242. package/dist/protocol.d.cts +0 -48
  243. package/dist/protocol.d.mts +0 -48
  244. package/dist/protocol.mjs +0 -17
  245. package/dist/shared/language-server.CO_nmHiL.cjs +0 -7689
  246. package/dist/shared/language-server.Da6ey08o.d.cts +0 -1619
  247. package/dist/shared/language-server.De7S3e5Z.d.ts +0 -1619
  248. package/dist/shared/language-server.Dj4iDjtB.d.mts +0 -1619
  249. package/dist/shared/language-server.oO_9JoAG.mjs +0 -7666
  250. package/src/validation/view-predicates/deployments.ts +0 -56
@@ -0,0 +1,428 @@
1
+ import type * as c4 from '@likec4/core'
2
+ import { invariant, isNonEmptyArray, nonexhaustive } from '@likec4/core'
3
+ import { isArray, isDefined, isNonNullish, isTruthy } from 'remeda'
4
+ import type { Writable } from 'type-fest'
5
+ import {
6
+ ast,
7
+ type ParsedAstDynamicView,
8
+ type ParsedAstElementView,
9
+ toAutoLayout,
10
+ toColor,
11
+ toElementStyle,
12
+ ViewOps
13
+ } from '../../ast'
14
+ import type { NotationProperty } from '../../generated/ast'
15
+ import { logger, logWarnError } from '../../logger'
16
+ import { stringHash } from '../../utils'
17
+ import { elementRef } from '../../utils/elementRef'
18
+ import { parseViewManualLayout } from '../../view-utils/manual-layout'
19
+ import { removeIndent, toSingleLine } from './Base'
20
+ import type { WithDeploymentView } from './DeploymentViewParser'
21
+ import type { WithPredicates } from './PredicatesParser'
22
+
23
+ export type WithViewsParser = ReturnType<typeof ViewsParser>
24
+
25
+ export function ViewsParser<TBase extends WithPredicates & WithDeploymentView>(B: TBase) {
26
+ return class ViewsParser extends B {
27
+ parseViews() {
28
+ const isValid = this.isValid
29
+ for (const viewBlock of this.doc.parseResult.value.views) {
30
+ const localStyles = viewBlock.styles.flatMap(s => {
31
+ try {
32
+ return isValid(s) ? this.parseViewRuleStyleOrGlobalRef(s) : []
33
+ } catch (e) {
34
+ logWarnError(e)
35
+ return []
36
+ }
37
+ })
38
+
39
+ for (const view of viewBlock.views) {
40
+ try {
41
+ if (!isValid(view)) {
42
+ continue
43
+ }
44
+ switch (true) {
45
+ case ast.isElementView(view):
46
+ this.doc.c4Views.push(this.parseElementView(view, localStyles))
47
+ break
48
+ case ast.isDynamicView(view):
49
+ this.doc.c4Views.push(this.parseDynamicElementView(view, localStyles))
50
+ break
51
+ case ast.isDeploymentView(view):
52
+ this.doc.c4Views.push(this.parseDeploymentView(view))
53
+ break
54
+ default:
55
+ nonexhaustive(view)
56
+ }
57
+ } catch (e) {
58
+ logWarnError(e)
59
+ }
60
+ }
61
+ }
62
+ }
63
+
64
+ parseElementView(astNode: ast.ElementView, additionalStyles: c4.ViewRuleStyleOrGlobalRef[]): ParsedAstElementView {
65
+ const body = astNode.body
66
+ invariant(body, 'ElementView body is not defined')
67
+ const astPath = this.getAstNodePath(astNode)
68
+
69
+ let viewOf = null as c4.Fqn | null
70
+ if ('viewOf' in astNode) {
71
+ const viewOfEl = elementRef(astNode.viewOf)
72
+ const _viewOf = viewOfEl && this.resolveFqn(viewOfEl)
73
+ if (!_viewOf) {
74
+ logger.warn('viewOf is not resolved: ' + astNode.$cstNode?.text)
75
+ } else {
76
+ viewOf = _viewOf
77
+ }
78
+ }
79
+
80
+ let id = astNode.name
81
+ if (!id) {
82
+ id = 'view_' + stringHash(
83
+ this.doc.uri.toString(),
84
+ astPath,
85
+ viewOf ?? ''
86
+ ) as c4.ViewId
87
+ }
88
+
89
+ const title = toSingleLine(body.props.find(p => p.key === 'title')?.value) ?? null
90
+ const description = removeIndent(body.props.find(p => p.key === 'description')?.value) ?? null
91
+
92
+ const tags = this.convertTags(body)
93
+ const links = this.convertLinks(body)
94
+
95
+ const manualLayout = parseViewManualLayout(astNode)
96
+
97
+ const view: ParsedAstElementView = {
98
+ __: 'element',
99
+ id: id as c4.ViewId,
100
+ astPath,
101
+ title,
102
+ description,
103
+ tags,
104
+ links: isNonEmptyArray(links) ? links : null,
105
+ rules: [
106
+ ...additionalStyles,
107
+ ...body.rules.flatMap(n => {
108
+ try {
109
+ return this.isValid(n) ? this.parseViewRule(n) : []
110
+ } catch (e) {
111
+ logWarnError(e)
112
+ return []
113
+ }
114
+ })
115
+ ],
116
+ ...(viewOf && { viewOf }),
117
+ ...(manualLayout && { manualLayout })
118
+ }
119
+ ViewOps.writeId(astNode, view.id)
120
+
121
+ if ('extends' in astNode) {
122
+ const extendsView = astNode.extends.view.ref
123
+ invariant(extendsView?.name, 'view extends is not resolved: ' + astNode.$cstNode?.text)
124
+ return Object.assign(view, {
125
+ extends: extendsView.name as c4.ViewId
126
+ })
127
+ }
128
+
129
+ return view
130
+ }
131
+
132
+ parseViewRule(astRule: ast.ViewRule): c4.ViewRule {
133
+ if (ast.isViewRulePredicate(astRule)) {
134
+ return this.parseViewRulePredicate(astRule)
135
+ }
136
+ if (ast.isViewRuleGlobalPredicateRef(astRule)) {
137
+ return this.parseViewRuleGlobalPredicateRef(astRule)
138
+ }
139
+ if (ast.isViewRuleStyleOrGlobalRef(astRule)) {
140
+ return this.parseViewRuleStyleOrGlobalRef(astRule)
141
+ }
142
+ if (ast.isViewRuleAutoLayout(astRule)) {
143
+ return toAutoLayout(astRule)
144
+ }
145
+ if (ast.isViewRuleGroup(astRule)) {
146
+ return this.parseViewRuleGroup(astRule)
147
+ }
148
+ nonexhaustive(astRule)
149
+ }
150
+
151
+ parseViewRulePredicate(astNode: ast.ViewRulePredicate): c4.ViewRulePredicate {
152
+ const exprs = [] as c4.Expression[]
153
+ let predicate = astNode.predicates
154
+ while (predicate) {
155
+ const { value, prev } = predicate
156
+ try {
157
+ if (isTruthy(value) && this.isValid(value as any)) {
158
+ exprs.unshift(this.parsePredicate(value))
159
+ }
160
+ } catch (e) {
161
+ logWarnError(e)
162
+ }
163
+ if (!prev) {
164
+ break
165
+ }
166
+ predicate = prev
167
+ }
168
+ return ast.isIncludePredicate(astNode) ? { include: exprs } : { exclude: exprs }
169
+ }
170
+
171
+ parseViewRuleGlobalPredicateRef(
172
+ astRule: ast.ViewRuleGlobalPredicateRef | ast.DynamicViewGlobalPredicateRef
173
+ ): c4.ViewRuleGlobalPredicateRef {
174
+ return {
175
+ predicateId: astRule.predicate.$refText as c4.GlobalPredicateId
176
+ }
177
+ }
178
+
179
+ parseViewRuleStyleOrGlobalRef(astRule: ast.ViewRuleStyleOrGlobalRef): c4.ViewRuleStyleOrGlobalRef {
180
+ if (ast.isViewRuleStyle(astRule)) {
181
+ return this.parseViewRuleStyle(astRule)
182
+ }
183
+ if (ast.isViewRuleGlobalStyle(astRule)) {
184
+ return this.parseViewRuleGlobalStyle(astRule)
185
+ }
186
+ nonexhaustive(astRule)
187
+ }
188
+
189
+ parseViewRuleGroup(astNode: ast.ViewRuleGroup): c4.ViewRuleGroup {
190
+ const groupRules = [] as c4.ViewRuleGroup['groupRules']
191
+ for (const rule of astNode.groupRules) {
192
+ try {
193
+ if (!this.isValid(rule)) {
194
+ continue
195
+ }
196
+ if (ast.isViewRulePredicate(rule)) {
197
+ groupRules.push(this.parseViewRulePredicate(rule))
198
+ continue
199
+ }
200
+ if (ast.isViewRuleGroup(rule)) {
201
+ groupRules.push(this.parseViewRuleGroup(rule))
202
+ continue
203
+ }
204
+ nonexhaustive(rule)
205
+ } catch (e) {
206
+ logWarnError(e)
207
+ }
208
+ }
209
+ return {
210
+ title: toSingleLine(astNode.title) ?? null,
211
+ groupRules,
212
+ ...toElementStyle(astNode.props, this.isValid)
213
+ }
214
+ }
215
+
216
+ parseViewRuleStyle(astRule: ast.ViewRuleStyle | ast.GlobalStyle): c4.ViewRuleStyle {
217
+ const styleProps = astRule.props.filter(ast.isStyleProperty)
218
+ const targets = astRule.target
219
+ const notation = astRule.props.find(ast.isNotationProperty)
220
+ return this.parseRuleStyle(styleProps, targets, notation)
221
+ }
222
+
223
+ parseRuleStyle(
224
+ styleProperties: ast.StyleProperty[],
225
+ elementExpressionsIterator: ast.ElementExpressionsIterator,
226
+ notationProperty?: NotationProperty
227
+ ): c4.ViewRuleStyle {
228
+ const styleProps = toElementStyle(styleProperties, this.isValid)
229
+ const notation = removeIndent(notationProperty?.value)
230
+ const targets = this.parseElementExpressionsIterator(elementExpressionsIterator)
231
+ return {
232
+ targets,
233
+ ...(notation && { notation }),
234
+ style: {
235
+ ...styleProps
236
+ }
237
+ }
238
+ }
239
+
240
+ parseViewRuleGlobalStyle(astRule: ast.ViewRuleGlobalStyle): c4.ViewRuleGlobalStyle {
241
+ return {
242
+ styleId: astRule.style.$refText as c4.GlobalStyleID
243
+ }
244
+ }
245
+
246
+ parseDynamicElementView(
247
+ astNode: ast.DynamicView,
248
+ additionalStyles: c4.ViewRuleStyleOrGlobalRef[]
249
+ ): ParsedAstDynamicView {
250
+ const body = astNode.body
251
+ invariant(body, 'DynamicElementView body is not defined')
252
+ // only valid props
253
+ const isValid = this.isValid
254
+ const props = body.props.filter(isValid)
255
+ const astPath = this.getAstNodePath(astNode)
256
+
257
+ let id = astNode.name
258
+ if (!id) {
259
+ id = 'dynamic_' + stringHash(
260
+ this.doc.uri.toString(),
261
+ astPath
262
+ ) as c4.ViewId
263
+ }
264
+
265
+ const title = toSingleLine(props.find(p => p.key === 'title')?.value) ?? null
266
+ const description = removeIndent(props.find(p => p.key === 'description')?.value) ?? null
267
+
268
+ const tags = this.convertTags(body)
269
+ const links = this.convertLinks(body)
270
+
271
+ ViewOps.writeId(astNode, id as c4.ViewId)
272
+
273
+ const manualLayout = parseViewManualLayout(astNode)
274
+
275
+ return {
276
+ __: 'dynamic',
277
+ id: id as c4.ViewId,
278
+ astPath,
279
+ title,
280
+ description,
281
+ tags,
282
+ links: isNonEmptyArray(links) ? links : null,
283
+ rules: [
284
+ ...additionalStyles,
285
+ ...body.rules.flatMap(n => {
286
+ try {
287
+ return isValid(n) ? this.parseDynamicViewRule(n) : []
288
+ } catch (e) {
289
+ logWarnError(e)
290
+ return []
291
+ }
292
+ }, [] as Array<c4.DynamicViewRule>)
293
+ ],
294
+ steps: body.steps.reduce((acc, n) => {
295
+ try {
296
+ if (isValid(n)) {
297
+ if (ast.isDynamicViewParallelSteps(n)) {
298
+ acc.push(this.parseDynamicParallelSteps(n))
299
+ } else {
300
+ acc.push(this.parseDynamicStep(n))
301
+ }
302
+ }
303
+ } catch (e) {
304
+ logWarnError(e)
305
+ }
306
+ return acc
307
+ }, [] as c4.DynamicViewStepOrParallel[]),
308
+ ...(manualLayout && { manualLayout })
309
+ }
310
+ }
311
+
312
+ parseDynamicViewRule(astRule: ast.DynamicViewRule): c4.DynamicViewRule {
313
+ if (ast.isDynamicViewIncludePredicate(astRule)) {
314
+ return this.parseDynamicViewIncludePredicate(astRule)
315
+ }
316
+ if (ast.isDynamicViewGlobalPredicateRef(astRule)) {
317
+ return this.parseViewRuleGlobalPredicateRef(astRule)
318
+ }
319
+ if (ast.isViewRuleStyleOrGlobalRef(astRule)) {
320
+ return this.parseViewRuleStyleOrGlobalRef(astRule)
321
+ }
322
+ if (ast.isViewRuleAutoLayout(astRule)) {
323
+ return toAutoLayout(astRule)
324
+ }
325
+ nonexhaustive(astRule)
326
+ }
327
+
328
+ parseDynamicViewIncludePredicate(astRule: ast.DynamicViewIncludePredicate): c4.DynamicViewIncludeRule {
329
+ const include = [] as c4.ElementPredicateExpression[]
330
+ let iter: ast.DynamicViewPredicateIterator | undefined = astRule.predicates
331
+ while (iter) {
332
+ try {
333
+ if (isNonNullish(iter.value) && this.isValid(iter.value as any)) {
334
+ const c4expr = this.parseElementPredicate(iter.value)
335
+ include.unshift(c4expr)
336
+ }
337
+ } catch (e) {
338
+ logWarnError(e)
339
+ }
340
+ iter = iter.prev
341
+ }
342
+ return { include }
343
+ }
344
+
345
+ parseDynamicParallelSteps(node: ast.DynamicViewParallelSteps): c4.DynamicViewParallelSteps {
346
+ return {
347
+ __parallel: node.steps.map(step => this.parseDynamicStep(step))
348
+ }
349
+ }
350
+
351
+ parseDynamicStep(node: ast.DynamicViewStep): c4.DynamicViewStep {
352
+ const sourceEl = elementRef(node.source)
353
+ if (!sourceEl) {
354
+ throw new Error('Invalid reference to source')
355
+ }
356
+ const targetEl = elementRef(node.target)
357
+ if (!targetEl) {
358
+ throw new Error('Invalid reference to target')
359
+ }
360
+ let source = this.resolveFqn(sourceEl)
361
+ let target = this.resolveFqn(targetEl)
362
+ const title = removeIndent(node.title) ?? null
363
+
364
+ let step: Writable<c4.DynamicViewStep> = {
365
+ source,
366
+ target,
367
+ title
368
+ }
369
+ if (node.isBackward) {
370
+ step = {
371
+ source: target,
372
+ target: source,
373
+ title,
374
+ isBackward: true
375
+ }
376
+ }
377
+ if (!isArray(node.custom?.props)) {
378
+ return step
379
+ }
380
+ for (const prop of node.custom.props) {
381
+ try {
382
+ switch (true) {
383
+ case ast.isRelationNavigateToProperty(prop): {
384
+ const viewId = prop.value.view.ref?.name
385
+ if (isTruthy(viewId)) {
386
+ step.navigateTo = viewId as c4.ViewId
387
+ }
388
+ break
389
+ }
390
+ case ast.isRelationStringProperty(prop):
391
+ case ast.isNotationProperty(prop):
392
+ case ast.isNotesProperty(prop): {
393
+ if (isDefined(prop.value)) {
394
+ step[prop.key] = removeIndent(prop.value) ?? ''
395
+ }
396
+ break
397
+ }
398
+ case ast.isArrowProperty(prop): {
399
+ if (isDefined(prop.value)) {
400
+ step[prop.key] = prop.value
401
+ }
402
+ break
403
+ }
404
+ case ast.isColorProperty(prop): {
405
+ const value = toColor(prop)
406
+ if (isDefined(value)) {
407
+ step[prop.key] = value
408
+ }
409
+ break
410
+ }
411
+ case ast.isLineProperty(prop): {
412
+ if (isDefined(prop.value)) {
413
+ step[prop.key] = prop.value
414
+ }
415
+ break
416
+ }
417
+ default:
418
+ nonexhaustive(prop)
419
+ }
420
+ }
421
+ catch (e) {
422
+ logWarnError(e)
423
+ }
424
+ }
425
+ return step
426
+ }
427
+ }
428
+ }
package/src/module.ts CHANGED
@@ -1,16 +1,27 @@
1
- import { DocumentCache, EmptyFileSystem, inject, type Module, WorkspaceCache } from 'langium'
1
+ import { GraphvizLayouter, GraphvizWasmAdapter } from '@likec4/layouts'
2
+ import {
3
+ type Module,
4
+ DocumentCache,
5
+ EmptyFileSystem,
6
+ inject,
7
+ WorkspaceCache,
8
+ } from 'langium'
2
9
  import {
3
- createDefaultModule,
4
- createDefaultSharedModule,
5
10
  type DefaultSharedModuleContext,
6
11
  type LangiumServices,
7
12
  type LangiumSharedServices,
8
13
  type PartialLangiumServices,
9
- type PartialLangiumSharedServices
14
+ type PartialLangiumSharedServices,
15
+ createDefaultModule,
16
+ createDefaultSharedModule,
10
17
  } from 'langium/lsp'
18
+ import { LikeC4DocumentationProvider } from './documentation'
11
19
  import { LikeC4Formatter } from './formatting/LikeC4Formatter'
12
- import { LikeC4GeneratedModule, LikeC4GeneratedSharedModule } from './generated/module'
13
- import { logErrorToTelemetry, logToLspConnection } from './logger'
20
+ import {
21
+ LikeC4GeneratedModule,
22
+ LikeC4GeneratedSharedModule,
23
+ } from './generated/module'
24
+ import { logger, logToLspConnection } from './logger'
14
25
  import {
15
26
  LikeC4CodeLensProvider,
16
27
  LikeC4CompletionProvider,
@@ -18,14 +29,29 @@ import {
18
29
  LikeC4DocumentLinkProvider,
19
30
  LikeC4DocumentSymbolProvider,
20
31
  LikeC4HoverProvider,
21
- LikeC4SemanticTokenProvider
32
+ LikeC4SemanticTokenProvider,
22
33
  } from './lsp'
23
- import { DeploymentsIndex, FqnIndex, LikeC4ModelBuilder, LikeC4ModelLocator, LikeC4ModelParser } from './model'
34
+ import {
35
+ DeploymentsIndex,
36
+ FqnIndex,
37
+ LikeC4ModelBuilder,
38
+ LikeC4ModelLocator,
39
+ LikeC4ModelParser,
40
+ } from './model'
24
41
  import { LikeC4ModelChanges } from './model-change/ModelChanges'
25
- import { LikeC4NameProvider, LikeC4ScopeComputation, LikeC4ScopeProvider } from './references'
42
+ import {
43
+ LikeC4NameProvider,
44
+ LikeC4ScopeComputation,
45
+ LikeC4ScopeProvider,
46
+ } from './references'
26
47
  import { Rpc } from './Rpc'
27
- import { LikeC4WorkspaceManager, NodeKindProvider, WorkspaceSymbolProvider } from './shared'
48
+ import {
49
+ LikeC4WorkspaceManager,
50
+ NodeKindProvider,
51
+ WorkspaceSymbolProvider,
52
+ } from './shared'
28
53
  import { registerValidationChecks } from './validation'
54
+ import { LikeC4Views } from './views'
29
55
 
30
56
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
31
57
  type Constructor<T, Arguments extends unknown[] = any[]> = new(...arguments_: Arguments) => T
@@ -48,22 +74,27 @@ const LikeC4SharedModule: Module<
48
74
  > = {
49
75
  lsp: {
50
76
  NodeKindProvider: services => new NodeKindProvider(services),
51
- WorkspaceSymbolProvider: services => new WorkspaceSymbolProvider(services)
77
+ WorkspaceSymbolProvider: services => new WorkspaceSymbolProvider(services),
52
78
  },
53
79
  workspace: {
54
- WorkspaceManager: services => new LikeC4WorkspaceManager(services)
55
- }
80
+ WorkspaceManager: services => new LikeC4WorkspaceManager(services),
81
+ },
56
82
  }
57
83
 
58
84
  /**
59
85
  * Declaration of custom services - add your own service classes here.
60
86
  */
61
87
  export interface LikeC4AddedServices {
88
+ documentation: {
89
+ DocumentationProvider: LikeC4DocumentationProvider
90
+ }
62
91
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
63
92
  WorkspaceCache: WorkspaceCache<string, any>
64
93
  DocumentCache: DocumentCache<string, any>
65
94
  Rpc: Rpc
66
95
  likec4: {
96
+ Views: LikeC4Views
97
+ Layouter: GraphvizLayouter
67
98
  DeploymentsIndex: DeploymentsIndex
68
99
  FqnIndex: FqnIndex
69
100
  ModelParser: LikeC4ModelParser
@@ -96,16 +127,24 @@ function bind<T>(Type: Constructor<T, [LikeC4Services]>) {
96
127
  }
97
128
 
98
129
  export const LikeC4Module: Module<LikeC4Services, PartialLangiumServices & LikeC4AddedServices> = {
130
+ documentation: {
131
+ DocumentationProvider: bind(LikeC4DocumentationProvider),
132
+ },
99
133
  WorkspaceCache: (services: LikeC4Services) => new WorkspaceCache(services.shared),
100
134
  DocumentCache: (services: LikeC4Services) => new DocumentCache(services.shared),
101
135
  Rpc: bind(Rpc),
102
136
  likec4: {
137
+ Layouter: (_services: LikeC4Services) => {
138
+ logger.debug('Creating GraphvizLayouter with GraphvizWasmAdapter')
139
+ return new GraphvizLayouter(new GraphvizWasmAdapter())
140
+ },
141
+ Views: bind(LikeC4Views),
103
142
  DeploymentsIndex: bind(DeploymentsIndex),
104
143
  ModelChanges: bind(LikeC4ModelChanges),
105
144
  FqnIndex: bind(FqnIndex),
106
145
  ModelParser: bind(LikeC4ModelParser),
107
146
  ModelBuilder: bind(LikeC4ModelBuilder),
108
- ModelLocator: bind(LikeC4ModelLocator)
147
+ ModelLocator: bind(LikeC4ModelLocator),
109
148
  },
110
149
  lsp: {
111
150
  // RenameProvider: bind(LikeC4RenameProvider),
@@ -116,22 +155,22 @@ export const LikeC4Module: Module<LikeC4Services, PartialLangiumServices & LikeC
116
155
  HoverProvider: bind(LikeC4HoverProvider),
117
156
  CodeLensProvider: bind(LikeC4CodeLensProvider),
118
157
  DocumentLinkProvider: bind(LikeC4DocumentLinkProvider),
119
- Formatter: bind(LikeC4Formatter)
158
+ Formatter: bind(LikeC4Formatter),
120
159
  },
121
160
  references: {
122
161
  NameProvider: bind(LikeC4NameProvider),
123
162
  ScopeComputation: bind(LikeC4ScopeComputation),
124
- ScopeProvider: bind(LikeC4ScopeProvider)
125
- }
163
+ ScopeProvider: bind(LikeC4ScopeProvider),
164
+ },
126
165
  }
127
166
 
128
167
  export type LanguageServicesContext = Partial<DefaultSharedModuleContext>
129
168
 
130
169
  export function createCustomLanguageServices<I1, I2, I3, I extends I1 & I2 & I3 & LikeC4Services>(
131
170
  context: LanguageServicesContext,
132
- module: Module<I, I1>,
171
+ module?: Module<I, I1>,
133
172
  module2?: Module<I, I2>,
134
- module3?: Module<I, I3>
173
+ module3?: Module<I, I3>,
135
174
  ): { shared: LikeC4SharedServices; likec4: I } {
136
175
  const shared = createSharedServices(context)
137
176
  const modules = [
@@ -140,7 +179,7 @@ export function createCustomLanguageServices<I1, I2, I3, I extends I1 & I2 & I3
140
179
  LikeC4Module,
141
180
  module,
142
181
  module2,
143
- module3
182
+ module3,
144
183
  ].reduce(_merge, {}) as Module<I>
145
184
 
146
185
  const likec4 = inject(modules)
@@ -161,17 +200,16 @@ export function createCustomLanguageServices<I1, I2, I3, I extends I1 & I2 & I3
161
200
  export function createSharedServices(context: LanguageServicesContext = {}): LikeC4SharedServices {
162
201
  const moduleContext: DefaultSharedModuleContext = {
163
202
  ...EmptyFileSystem,
164
- ...context
203
+ ...context,
165
204
  }
166
205
  if (context.connection) {
167
206
  logToLspConnection(context.connection)
168
- logErrorToTelemetry(context.connection)
169
207
  }
170
208
 
171
209
  return inject(
172
210
  createDefaultSharedModule(moduleContext),
173
211
  LikeC4GeneratedSharedModule,
174
- LikeC4SharedModule
212
+ LikeC4SharedModule,
175
213
  )
176
214
  }
177
215
 
@@ -180,11 +218,19 @@ export function createLanguageServices(context: LanguageServicesContext = {}): {
180
218
  likec4: LikeC4Services
181
219
  } {
182
220
  const shared = createSharedServices(context)
183
- const likec4 = inject(createDefaultModule({ shared }), LikeC4GeneratedModule, LikeC4Module)
221
+ const likec4 = inject(
222
+ createDefaultModule({ shared }),
223
+ LikeC4GeneratedModule,
224
+ LikeC4Module,
225
+ )
184
226
  shared.ServiceRegistry.register(likec4)
185
227
  registerValidationChecks(likec4)
186
228
 
187
- if (context.connection) {
229
+ if (!context.connection) {
230
+ // We don't run inside a language server
231
+ // Therefore, initialize the configuration provider instantly
232
+ shared.workspace.ConfigurationProvider.initialized({})
233
+ } else {
188
234
  likec4.Rpc.init()
189
235
  }
190
236
 
package/src/protocol.ts CHANGED
@@ -1,11 +1,12 @@
1
1
  import type {
2
2
  ComputedLikeC4Model,
3
3
  ComputedView,
4
+ DiagramView,
4
5
  Fqn,
5
6
  ParsedLikeC4Model,
6
7
  RelationId,
7
8
  ViewChange,
8
- ViewId
9
+ ViewId,
9
10
  } from '@likec4/core'
10
11
  import { NotificationType, RequestType, RequestType0 } from 'vscode-jsonrpc'
11
12
  import type { DocumentUri, Location } from 'vscode-languageserver-types'
@@ -16,8 +17,9 @@ export type OnDidChangeModelNotification = typeof onDidChangeModel
16
17
  // #endregion
17
18
 
18
19
  // #region To server
20
+
19
21
  export const fetchModel = new RequestType0<{ model: ParsedLikeC4Model | null }, void>(
20
- 'likec4/fetchModel'
22
+ 'likec4/fetchModel',
21
23
  )
22
24
  export type FetchModelRequest = typeof fetchModel
23
25
 
@@ -26,21 +28,44 @@ export const fetchComputedModel = new RequestType<
26
28
  { model: ComputedLikeC4Model | null },
27
29
  void
28
30
  >(
29
- 'likec4/fetchComputedModel'
31
+ 'likec4/fetchComputedModel',
30
32
  )
31
33
  export type FetchComputedModelRequest = typeof fetchComputedModel
32
34
 
33
35
  export const computeView = new RequestType<{ viewId: ViewId }, { view: ComputedView | null }, void>(
34
- 'likec4/computeView'
36
+ 'likec4/computeView',
35
37
  )
36
38
  export type ComputeViewRequest = typeof computeView
37
39
 
40
+ /**
41
+ * Request to layout a view.
42
+ */
43
+ export const layoutView = new RequestType<
44
+ { viewId: ViewId },
45
+ {
46
+ result:
47
+ | {
48
+ dot: string
49
+ diagram: DiagramView
50
+ }
51
+ | null
52
+ },
53
+ void
54
+ >('likec4/layout-view')
55
+ export type LayoutViewRequest = typeof layoutView
56
+
57
+ /**
58
+ * Request to build documents.
59
+ */
38
60
  export interface BuildDocumentsParams {
39
61
  docs: DocumentUri[]
40
62
  }
41
63
  export const buildDocuments = new RequestType<BuildDocumentsParams, void, void>('likec4/build')
42
64
  export type BuildDocumentsRequest = typeof buildDocuments
43
65
 
66
+ /**
67
+ * Request to locate an element, relation, deployment or view.
68
+ */
44
69
  export type LocateParams =
45
70
  | {
46
71
  element: Fqn