@likec4/language-server 1.2.0 → 1.2.2

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 (173) hide show
  1. package/package.json +8 -10
  2. package/src/Rpc.ts +108 -0
  3. package/src/ast.ts +443 -0
  4. package/src/browser/index.ts +30 -0
  5. package/src/elementRef.ts +26 -0
  6. package/src/generated/ast.ts +1632 -0
  7. package/src/generated/grammar.ts +10 -0
  8. package/src/generated/module.ts +32 -0
  9. package/src/index.ts +4 -0
  10. package/src/like-c4.langium +395 -0
  11. package/src/logger.ts +54 -0
  12. package/src/lsp/CodeLensProvider.ts +51 -0
  13. package/src/lsp/DocumentHighlightProvider.ts +12 -0
  14. package/src/lsp/DocumentLinkProvider.test.ts +66 -0
  15. package/src/lsp/DocumentLinkProvider.ts +53 -0
  16. package/src/lsp/DocumentSymbolProvider.ts +201 -0
  17. package/src/lsp/HoverProvider.ts +58 -0
  18. package/{dist/lsp/SemanticTokenProvider.js → src/lsp/SemanticTokenProvider.ts} +57 -42
  19. package/src/lsp/index.ts +6 -0
  20. package/src/model/fqn-computation.ts +47 -0
  21. package/src/model/fqn-index.ts +161 -0
  22. package/src/model/index.ts +5 -0
  23. package/src/model/model-builder.ts +447 -0
  24. package/src/model/model-locator.ts +130 -0
  25. package/src/model/model-parser.ts +580 -0
  26. package/src/model-change/ModelChanges.ts +120 -0
  27. package/src/model-change/changeElementStyle.ts +176 -0
  28. package/src/model-change/changeViewLayout.ts +41 -0
  29. package/src/module.ts +197 -0
  30. package/src/node/index.ts +20 -0
  31. package/src/protocol.ts +87 -0
  32. package/src/references/index.ts +2 -0
  33. package/src/references/scope-computation.ts +142 -0
  34. package/src/references/scope-provider.ts +166 -0
  35. package/src/shared/NodeKindProvider.ts +67 -0
  36. package/src/shared/WorkspaceManager.ts +39 -0
  37. package/src/shared/WorkspaceSymbolProvider.ts +3 -0
  38. package/src/shared/index.ts +3 -0
  39. package/src/test/index.ts +1 -0
  40. package/src/test/testServices.ts +119 -0
  41. package/src/utils/index.ts +1 -0
  42. package/src/utils/printDocs.ts +3 -0
  43. package/src/utils/stringHash.ts +6 -0
  44. package/{dist/validation/dynamic-view-rule.js → src/validation/dynamic-view-rule.ts} +14 -11
  45. package/src/validation/dynamic-view-step.ts +39 -0
  46. package/src/validation/element.ts +52 -0
  47. package/{dist/validation/index.js → src/validation/index.ts} +22 -18
  48. package/src/validation/property-checks.ts +17 -0
  49. package/src/validation/relation.ts +57 -0
  50. package/src/validation/specification.ts +118 -0
  51. package/src/validation/view-predicates/custom-element-expr.ts +21 -0
  52. package/{dist/validation/view-predicates/expanded-element.js → src/validation/view-predicates/expanded-element.ts} +18 -13
  53. package/src/validation/view-predicates/incoming.ts +19 -0
  54. package/src/validation/view-predicates/index.ts +4 -0
  55. package/src/validation/view-predicates/outgoing.ts +19 -0
  56. package/src/validation/view.ts +26 -0
  57. package/src/view-utils/assignNavigateTo.ts +30 -0
  58. package/src/view-utils/index.ts +3 -0
  59. package/src/view-utils/resolve-extended-views.ts +57 -0
  60. package/src/view-utils/resolve-relative-paths.ts +84 -0
  61. package/dist/Rpc.d.ts +0 -10
  62. package/dist/Rpc.js +0 -98
  63. package/dist/ast.d.ts +0 -149
  64. package/dist/ast.js +0 -271
  65. package/dist/browser/index.d.ts +0 -9
  66. package/dist/browser/index.js +0 -16
  67. package/dist/elementRef.d.ts +0 -12
  68. package/dist/elementRef.js +0 -15
  69. package/dist/generated/ast.d.ts +0 -615
  70. package/dist/generated/ast.js +0 -957
  71. package/dist/generated/grammar.d.ts +0 -7
  72. package/dist/generated/grammar.js +0 -3
  73. package/dist/generated/module.d.ts +0 -14
  74. package/dist/generated/module.js +0 -22
  75. package/dist/index.d.ts +0 -5
  76. package/dist/index.js +0 -2
  77. package/dist/logger.d.ts +0 -12
  78. package/dist/logger.js +0 -51
  79. package/dist/lsp/CodeLensProvider.d.ts +0 -10
  80. package/dist/lsp/CodeLensProvider.js +0 -40
  81. package/dist/lsp/DocumentHighlightProvider.d.ts +0 -10
  82. package/dist/lsp/DocumentHighlightProvider.js +0 -10
  83. package/dist/lsp/DocumentLinkProvider.d.ts +0 -11
  84. package/dist/lsp/DocumentLinkProvider.js +0 -41
  85. package/dist/lsp/DocumentLinkProvider.test.d.ts +0 -2
  86. package/dist/lsp/DocumentLinkProvider.test.js +0 -54
  87. package/dist/lsp/DocumentSymbolProvider.d.ts +0 -22
  88. package/dist/lsp/DocumentSymbolProvider.js +0 -189
  89. package/dist/lsp/HoverProvider.d.ts +0 -10
  90. package/dist/lsp/HoverProvider.js +0 -36
  91. package/dist/lsp/SemanticTokenProvider.d.ts +0 -8
  92. package/dist/lsp/index.d.ts +0 -7
  93. package/dist/lsp/index.js +0 -6
  94. package/dist/model/fqn-computation.d.ts +0 -4
  95. package/dist/model/fqn-computation.js +0 -43
  96. package/dist/model/fqn-index.d.ts +0 -26
  97. package/dist/model/fqn-index.js +0 -114
  98. package/dist/model/index.d.ts +0 -6
  99. package/dist/model/index.js +0 -5
  100. package/dist/model/model-builder.d.ts +0 -20
  101. package/dist/model/model-builder.js +0 -365
  102. package/dist/model/model-locator.d.ts +0 -22
  103. package/dist/model/model-locator.js +0 -115
  104. package/dist/model/model-parser.d.ts +0 -29
  105. package/dist/model/model-parser.js +0 -520
  106. package/dist/model-change/ModelChanges.d.ts +0 -16
  107. package/dist/model-change/ModelChanges.js +0 -106
  108. package/dist/model-change/changeElementStyle.d.ts +0 -18
  109. package/dist/model-change/changeElementStyle.js +0 -141
  110. package/dist/model-change/changeViewLayout.d.ts +0 -13
  111. package/dist/model-change/changeViewLayout.js +0 -29
  112. package/dist/module.d.ts +0 -59
  113. package/dist/module.js +0 -121
  114. package/dist/node/index.d.ts +0 -6
  115. package/dist/node/index.js +0 -13
  116. package/dist/protocol.d.ts +0 -58
  117. package/dist/protocol.js +0 -14
  118. package/dist/references/index.d.ts +0 -3
  119. package/dist/references/index.js +0 -2
  120. package/dist/references/scope-computation.d.ts +0 -11
  121. package/dist/references/scope-computation.js +0 -111
  122. package/dist/references/scope-provider.d.ts +0 -18
  123. package/dist/references/scope-provider.js +0 -136
  124. package/dist/shared/NodeKindProvider.d.ts +0 -16
  125. package/dist/shared/NodeKindProvider.js +0 -60
  126. package/dist/shared/WorkspaceManager.d.ts +0 -17
  127. package/dist/shared/WorkspaceManager.js +0 -29
  128. package/dist/shared/WorkspaceSymbolProvider.d.ts +0 -4
  129. package/dist/shared/WorkspaceSymbolProvider.js +0 -3
  130. package/dist/shared/index.d.ts +0 -4
  131. package/dist/shared/index.js +0 -3
  132. package/dist/test/index.d.ts +0 -2
  133. package/dist/test/index.js +0 -1
  134. package/dist/test/testServices.d.ts +0 -23
  135. package/dist/test/testServices.js +0 -102
  136. package/dist/utils/index.d.ts +0 -2
  137. package/dist/utils/index.js +0 -1
  138. package/dist/utils/printDocs.d.ts +0 -3
  139. package/dist/utils/printDocs.js +0 -1
  140. package/dist/utils/stringHash.d.ts +0 -2
  141. package/dist/utils/stringHash.js +0 -5
  142. package/dist/validation/dynamic-view-rule.d.ts +0 -5
  143. package/dist/validation/dynamic-view-step.d.ts +0 -5
  144. package/dist/validation/dynamic-view-step.js +0 -33
  145. package/dist/validation/element.d.ts +0 -6
  146. package/dist/validation/element.js +0 -38
  147. package/dist/validation/index.d.ts +0 -3
  148. package/dist/validation/property-checks.d.ts +0 -5
  149. package/dist/validation/property-checks.js +0 -11
  150. package/dist/validation/relation.d.ts +0 -5
  151. package/dist/validation/relation.js +0 -50
  152. package/dist/validation/specification.d.ts +0 -10
  153. package/dist/validation/specification.js +0 -97
  154. package/dist/validation/view-predicates/custom-element-expr.d.ts +0 -5
  155. package/dist/validation/view-predicates/custom-element-expr.js +0 -16
  156. package/dist/validation/view-predicates/expanded-element.d.ts +0 -5
  157. package/dist/validation/view-predicates/incoming.d.ts +0 -5
  158. package/dist/validation/view-predicates/incoming.js +0 -14
  159. package/dist/validation/view-predicates/index.d.ts +0 -5
  160. package/dist/validation/view-predicates/index.js +0 -4
  161. package/dist/validation/view-predicates/outgoing.d.ts +0 -5
  162. package/dist/validation/view-predicates/outgoing.js +0 -14
  163. package/dist/validation/view.d.ts +0 -5
  164. package/dist/validation/view.js +0 -16
  165. package/dist/view-utils/assignNavigateTo.d.ts +0 -3
  166. package/dist/view-utils/assignNavigateTo.js +0 -24
  167. package/dist/view-utils/index.d.ts +0 -4
  168. package/dist/view-utils/index.js +0 -3
  169. package/dist/view-utils/resolve-extended-views.d.ts +0 -7
  170. package/dist/view-utils/resolve-extended-views.js +0 -41
  171. package/dist/view-utils/resolve-relative-paths.d.ts +0 -3
  172. package/dist/view-utils/resolve-relative-paths.js +0 -75
  173. /package/{dist → src}/reset.d.ts +0 -0
@@ -1,520 +0,0 @@
1
- import { InvalidModelError, invariant, isNonEmptyArray, nonexhaustive } from "@likec4/core";
2
- import { AstUtils } from "langium";
3
- import { isTruthy } from "remeda";
4
- import stripIndent from "strip-indent";
5
- import {
6
- ast,
7
- checksFromDiagnostics,
8
- cleanParsedModel,
9
- isFqnIndexedDocument,
10
- parseAstOpacityProperty,
11
- resolveRelationPoints,
12
- streamModel,
13
- toAutoLayout,
14
- toElementStyle,
15
- toRelationshipStyleExcludeDefaults,
16
- ViewOps
17
- } from "../ast.js";
18
- import { elementRef, getFqnElementRef } from "../elementRef.js";
19
- import { logError, logger, logWarnError } from "../logger.js";
20
- import { stringHash } from "../utils/index.js";
21
- const { getDocument } = AstUtils;
22
- function toSingleLine(str) {
23
- return str ? removeIndent(str).split("\n").join(" ") : void 0;
24
- }
25
- function removeIndent(str) {
26
- return str ? stripIndent(str).trim() : void 0;
27
- }
28
- export class LikeC4ModelParser {
29
- constructor(services) {
30
- this.services = services;
31
- this.fqnIndex = services.likec4.FqnIndex;
32
- logger.debug(`[ModelParser] Created`);
33
- }
34
- fqnIndex;
35
- parse(doc) {
36
- const docs = Array.isArray(doc) ? doc : [doc];
37
- const result = [];
38
- for (const doc2 of docs) {
39
- if (!isFqnIndexedDocument(doc2)) {
40
- logger.warn(`Not a FqnIndexedDocument: ${doc2.uri.toString(true)}`);
41
- continue;
42
- }
43
- try {
44
- result.push(this.parseLikeC4Document(doc2));
45
- } catch (cause) {
46
- logError(new InvalidModelError(`Error parsing document ${doc2.uri.toString()}`, { cause }));
47
- }
48
- }
49
- return result;
50
- }
51
- parseLikeC4Document(_doc) {
52
- const doc = cleanParsedModel(_doc);
53
- const { isValid } = checksFromDiagnostics(doc);
54
- this.parseSpecification(doc, isValid);
55
- this.parseModel(doc, isValid);
56
- this.parseViews(doc, isValid);
57
- return doc;
58
- }
59
- parseSpecification(doc, isValid) {
60
- const { parseResult, c4Specification } = doc;
61
- const specifications = parseResult.value.specifications.filter(isValid);
62
- const element_specs = specifications.flatMap((s) => s.elements.filter(isValid));
63
- for (const { kind, style } of element_specs) {
64
- try {
65
- const kindName = kind.name;
66
- c4Specification.kinds[kindName] = {
67
- ...c4Specification.kinds[kindName],
68
- ...toElementStyle(style?.props)
69
- };
70
- } catch (e) {
71
- logWarnError(e);
72
- }
73
- }
74
- const relations_specs = specifications.flatMap((s) => s.relationships.filter(isValid));
75
- for (const { kind, props } of relations_specs) {
76
- try {
77
- const kindName = kind.name;
78
- c4Specification.relationships[kindName] = {
79
- ...c4Specification.relationships[kindName],
80
- ...toRelationshipStyleExcludeDefaults(props)
81
- };
82
- } catch (e) {
83
- logWarnError(e);
84
- }
85
- }
86
- }
87
- parseModel(doc, isValid) {
88
- for (const el of streamModel(doc, isValid)) {
89
- if (ast.isElement(el)) {
90
- try {
91
- doc.c4Elements.push(this.parseElement(el));
92
- } catch (e) {
93
- logWarnError(e);
94
- }
95
- continue;
96
- }
97
- if (ast.isRelation(el)) {
98
- try {
99
- doc.c4Relations.push(this.parseRelation(el));
100
- } catch (e) {
101
- logWarnError(e);
102
- }
103
- continue;
104
- }
105
- nonexhaustive(el);
106
- }
107
- }
108
- parseElement(astNode) {
109
- const id = this.resolveFqn(astNode);
110
- const kind = astNode.kind.$refText;
111
- const tags = this.convertTags(astNode.body);
112
- const stylePropsAst = astNode.body?.props.find(ast.isStyleProperties)?.props;
113
- const style = toElementStyle(stylePropsAst);
114
- const astPath = this.getAstNodePath(astNode);
115
- let [title, description, technology] = astNode.props ?? [];
116
- const bodyProps = astNode.body?.props.filter(ast.isElementStringProperty) ?? [];
117
- title = toSingleLine(title ?? bodyProps.find((p) => p.key === "title")?.value);
118
- description = removeIndent(description ?? bodyProps.find((p) => p.key === "description")?.value);
119
- technology = toSingleLine(technology ?? bodyProps.find((p) => p.key === "technology")?.value);
120
- const links = astNode.body?.props.filter(ast.isLinkProperty).map((p) => p.value);
121
- return {
122
- id,
123
- kind,
124
- astPath,
125
- title: title ?? astNode.name,
126
- ...tags && { tags },
127
- ...links && isNonEmptyArray(links) && { links },
128
- ...isTruthy(technology) && { technology },
129
- ...isTruthy(description) && { description },
130
- style
131
- };
132
- }
133
- parseRelation(astNode) {
134
- const coupling = resolveRelationPoints(astNode);
135
- const target = this.resolveFqn(coupling.target);
136
- const source = this.resolveFqn(coupling.source);
137
- const tags = this.convertTags(astNode) ?? this.convertTags(astNode.body);
138
- const links = astNode.body?.props.filter(ast.isLinkProperty).map((p) => p.value);
139
- const kind = astNode.kind?.ref?.name;
140
- const astPath = this.getAstNodePath(astNode);
141
- const title = toSingleLine(
142
- astNode.title ?? astNode.body?.props.find((p) => p.key === "title")?.value
143
- ) ?? "";
144
- const styleProp = astNode.body?.props.find(ast.isRelationStyleProperty);
145
- const id = stringHash(
146
- astPath,
147
- source,
148
- target
149
- );
150
- return {
151
- id,
152
- astPath,
153
- source,
154
- target,
155
- title,
156
- ...kind && { kind },
157
- ...tags && { tags },
158
- ...isNonEmptyArray(links) && { links },
159
- ...toRelationshipStyleExcludeDefaults(styleProp?.props)
160
- };
161
- }
162
- parseViews(doc, isValid) {
163
- const views = doc.parseResult.value.views.flatMap((v) => isValid(v) ? v.views : []);
164
- for (const view of views) {
165
- try {
166
- if (!isValid(view)) {
167
- continue;
168
- }
169
- doc.c4Views.push(
170
- ast.isElementView(view) ? this.parseElementView(view, isValid) : this.parseDynamicElementView(view, isValid)
171
- );
172
- } catch (e) {
173
- logWarnError(e);
174
- }
175
- }
176
- }
177
- parseElementExpr(astNode) {
178
- if (ast.isWildcardExpr(astNode)) {
179
- return {
180
- wildcard: true
181
- };
182
- }
183
- if (ast.isElementKindExpr(astNode)) {
184
- return {
185
- elementKind: astNode.kind.$refText,
186
- isEqual: astNode.isEqual
187
- };
188
- }
189
- if (ast.isElementTagExpr(astNode)) {
190
- let elementTag = astNode.tag.$refText;
191
- if (elementTag.startsWith("#")) {
192
- elementTag = elementTag.slice(1);
193
- }
194
- return {
195
- elementTag,
196
- isEqual: astNode.isEqual
197
- };
198
- }
199
- if (ast.isExpandElementExpr(astNode)) {
200
- const elementNode = elementRef(astNode.parent);
201
- invariant(elementNode, "Element not found " + astNode.parent.$cstNode?.text);
202
- const expanded = this.resolveFqn(elementNode);
203
- return {
204
- expanded
205
- };
206
- }
207
- if (ast.isDescedantsExpr(astNode)) {
208
- const elementNode = elementRef(astNode.parent);
209
- invariant(elementNode, "Element not found " + astNode.parent.$cstNode?.text);
210
- const element = this.resolveFqn(elementNode);
211
- return {
212
- element,
213
- isDescedants: true
214
- };
215
- }
216
- if (ast.isElementRef(astNode)) {
217
- const elementNode = elementRef(astNode);
218
- invariant(elementNode, "Element not found " + astNode.$cstNode?.text);
219
- const element = this.resolveFqn(elementNode);
220
- return {
221
- element
222
- };
223
- }
224
- nonexhaustive(astNode);
225
- }
226
- parseCustomElementExpr(astNode) {
227
- let targetRef;
228
- if (ast.isElementRef(astNode.target)) {
229
- targetRef = astNode.target;
230
- } else if (ast.isExpandElementExpr(astNode.target)) {
231
- targetRef = astNode.target.parent;
232
- } else {
233
- invariant(false, "ElementRef expected as target of custom element");
234
- }
235
- const elementNode = elementRef(targetRef);
236
- invariant(elementNode, "element not found: " + astNode.$cstNode?.text);
237
- const element = this.resolveFqn(elementNode);
238
- const props = astNode.body?.props ?? [];
239
- return props.reduce(
240
- (acc, prop) => {
241
- if (ast.isNavigateToProperty(prop)) {
242
- const viewId = prop.value.view.$refText;
243
- if (isTruthy(viewId)) {
244
- acc.custom.navigateTo = viewId;
245
- }
246
- return acc;
247
- }
248
- if (ast.isElementStringProperty(prop)) {
249
- const value = prop.key === "description" ? removeIndent(prop.value) : toSingleLine(prop.value);
250
- acc.custom[prop.key] = value.trim();
251
- return acc;
252
- }
253
- if (ast.isIconProperty(prop)) {
254
- acc.custom[prop.key] = prop.value;
255
- return acc;
256
- }
257
- if (ast.isColorProperty(prop)) {
258
- acc.custom[prop.key] = prop.value;
259
- return acc;
260
- }
261
- if (ast.isShapeProperty(prop)) {
262
- acc.custom[prop.key] = prop.value;
263
- return acc;
264
- }
265
- if (ast.isBorderProperty(prop)) {
266
- acc.custom[prop.key] = prop.value;
267
- return acc;
268
- }
269
- if (ast.isOpacityProperty(prop)) {
270
- acc.custom[prop.key] = parseAstOpacityProperty(prop);
271
- return acc;
272
- }
273
- nonexhaustive(prop);
274
- },
275
- {
276
- custom: {
277
- element
278
- }
279
- }
280
- );
281
- }
282
- parsePredicateExpr(astNode) {
283
- if (ast.isRelationExpr(astNode)) {
284
- return {
285
- source: this.parseElementExpr(astNode.source),
286
- target: this.parseElementExpr(astNode.target),
287
- isBidirectional: astNode.isBidirectional
288
- };
289
- }
290
- if (ast.isInOutExpr(astNode)) {
291
- return {
292
- inout: this.parseElementExpr(astNode.inout.to)
293
- };
294
- }
295
- if (ast.isOutgoingExpr(astNode)) {
296
- return {
297
- outgoing: this.parseElementExpr(astNode.from)
298
- };
299
- }
300
- if (ast.isIncomingExpr(astNode)) {
301
- return {
302
- incoming: this.parseElementExpr(astNode.to)
303
- };
304
- }
305
- if (ast.isCustomElementExpr(astNode)) {
306
- return this.parseCustomElementExpr(astNode);
307
- }
308
- if (ast.isElementExpr(astNode)) {
309
- return this.parseElementExpr(astNode);
310
- }
311
- nonexhaustive(astNode);
312
- }
313
- parseViewRule(astRule, isValid) {
314
- if (ast.isIncludePredicate(astRule) || ast.isExcludePredicate(astRule)) {
315
- const exprs = astRule.expressions.flatMap((n) => {
316
- try {
317
- return isValid(n) ? this.parsePredicateExpr(n) : [];
318
- } catch (e) {
319
- logWarnError(e);
320
- return [];
321
- }
322
- });
323
- return ast.isIncludePredicate(astRule) ? { include: exprs } : { exclude: exprs };
324
- }
325
- if (ast.isViewRuleStyle(astRule)) {
326
- const styleProps = toElementStyle(astRule.styleprops);
327
- return {
328
- targets: astRule.targets.map((n) => this.parseElementExpr(n)),
329
- style: {
330
- ...styleProps
331
- }
332
- };
333
- }
334
- if (ast.isViewRuleAutoLayout(astRule)) {
335
- return {
336
- autoLayout: toAutoLayout(astRule.direction)
337
- };
338
- }
339
- nonexhaustive(astRule);
340
- }
341
- parseDynamicStep(node) {
342
- const sourceEl = elementRef(node.source);
343
- if (!sourceEl) {
344
- throw new Error("Invalid reference to source");
345
- }
346
- const targetEl = elementRef(node.target);
347
- if (!targetEl) {
348
- throw new Error("Invalid reference to target");
349
- }
350
- let source = this.resolveFqn(sourceEl);
351
- let target = this.resolveFqn(targetEl);
352
- if (node.isBackward) {
353
- ;
354
- [source, target] = [target, source];
355
- }
356
- const title = toSingleLine(node.title) ?? null;
357
- return {
358
- source,
359
- target,
360
- title,
361
- isBackward: node.isBackward
362
- };
363
- }
364
- parseElementView(astNode, isValid) {
365
- const body = astNode.body;
366
- invariant(body, "ElementView body is not defined");
367
- const astPath = this.getAstNodePath(astNode);
368
- let viewOf = null;
369
- if ("viewOf" in astNode) {
370
- const viewOfEl = elementRef(astNode.viewOf);
371
- const _viewOf = viewOfEl && this.resolveFqn(viewOfEl);
372
- if (!_viewOf) {
373
- logger.warn("viewOf is not resolved: " + astNode.$cstNode?.text);
374
- } else {
375
- viewOf = _viewOf;
376
- }
377
- }
378
- let id = astNode.name;
379
- if (!id) {
380
- id = "view_" + stringHash(
381
- getDocument(astNode).uri.toString(),
382
- astPath,
383
- viewOf ?? ""
384
- );
385
- }
386
- const title = toSingleLine(body.props.find((p) => p.key === "title")?.value) ?? null;
387
- const description = removeIndent(body.props.find((p) => p.key === "description")?.value) ?? null;
388
- const tags = this.convertTags(body);
389
- const links = body.props.filter(ast.isLinkProperty).map((p) => p.value);
390
- const view = {
391
- __: "element",
392
- id,
393
- astPath,
394
- ...viewOf && { viewOf },
395
- title,
396
- description,
397
- tags,
398
- links: isNonEmptyArray(links) ? links : null,
399
- rules: body.rules.flatMap((n) => {
400
- try {
401
- return isValid(n) ? this.parseViewRule(n, isValid) : [];
402
- } catch (e) {
403
- logWarnError(e);
404
- return [];
405
- }
406
- })
407
- };
408
- ViewOps.writeId(astNode, view.id);
409
- if ("extends" in astNode) {
410
- const extendsView = astNode.extends.view.ref;
411
- invariant(extendsView?.name, "view extends is not resolved: " + astNode.$cstNode?.text);
412
- return Object.assign(view, {
413
- extends: extendsView.name
414
- });
415
- }
416
- return view;
417
- }
418
- parseDynamicElementView(astNode, isValid) {
419
- const body = astNode.body;
420
- invariant(body, "ElementView body is not defined");
421
- const props = body.props.filter(isValid);
422
- const astPath = this.getAstNodePath(astNode);
423
- let id = astNode.name;
424
- if (!id) {
425
- id = "dynamic_" + stringHash(
426
- getDocument(astNode).uri.toString(),
427
- astPath
428
- );
429
- }
430
- const title = toSingleLine(props.find((p) => p.key === "title")?.value) ?? null;
431
- const description = removeIndent(props.find((p) => p.key === "description")?.value) ?? null;
432
- const tags = this.convertTags(body);
433
- const links = props.filter(ast.isLinkProperty).map((p) => p.value);
434
- ViewOps.writeId(astNode, id);
435
- return {
436
- __: "dynamic",
437
- id,
438
- astPath,
439
- title,
440
- description,
441
- tags,
442
- links: isNonEmptyArray(links) ? links : null,
443
- rules: body.rules.reduce((acc, n) => {
444
- if (!isValid(n)) {
445
- return acc;
446
- }
447
- try {
448
- if (ast.isDynamicViewRulePredicate(n)) {
449
- const include = [];
450
- for (const expr of n.expressions) {
451
- if (ast.isElementExpr(expr)) {
452
- include.push(this.parseElementExpr(expr));
453
- continue;
454
- }
455
- if (ast.isCustomElementExpr(expr)) {
456
- include.push(this.parseCustomElementExpr(expr));
457
- continue;
458
- }
459
- }
460
- if (include.length > 0) {
461
- acc.push({ include });
462
- }
463
- return acc;
464
- }
465
- if (ast.isViewRuleStyle(n)) {
466
- const styleProps = toElementStyle(n.styleprops);
467
- const targets = n.targets.map((n2) => this.parseElementExpr(n2));
468
- if (targets.length > 0) {
469
- acc.push({
470
- targets,
471
- style: {
472
- ...styleProps
473
- }
474
- });
475
- }
476
- return acc;
477
- }
478
- if (ast.isViewRuleAutoLayout(n)) {
479
- acc.push({
480
- autoLayout: toAutoLayout(n.direction)
481
- });
482
- return acc;
483
- }
484
- nonexhaustive(n);
485
- } catch (e) {
486
- logWarnError(e);
487
- return acc;
488
- }
489
- }, []),
490
- steps: body.steps.reduce((acc, n) => {
491
- try {
492
- if (isValid(n)) {
493
- acc.push(this.parseDynamicStep(n));
494
- }
495
- } catch (e) {
496
- logWarnError(e);
497
- }
498
- return acc;
499
- }, [])
500
- };
501
- }
502
- resolveFqn(node) {
503
- if (ast.isExtendElement(node)) {
504
- return getFqnElementRef(node.element);
505
- }
506
- const fqn = this.fqnIndex.getFqn(node);
507
- invariant(fqn, `Not indexed element: ${this.getAstNodePath(node)}`);
508
- return fqn;
509
- }
510
- getAstNodePath(node) {
511
- return this.services.workspace.AstNodeLocator.getAstNodePath(node);
512
- }
513
- convertTags(withTags) {
514
- if (!withTags) {
515
- return null;
516
- }
517
- const tags = withTags.tags?.value.flatMap(({ ref }) => ref ? ref.name : []);
518
- return isNonEmptyArray(tags) ? tags : null;
519
- }
520
- }
@@ -1,16 +0,0 @@
1
- import { Location, Range, TextEdit } from 'vscode-languageserver-protocol';
2
- import { type ParsedLikeC4LangiumDocument } from '../ast';
3
- import type { LikeC4Services } from '../module';
4
- import type { ChangeViewRequestParams } from '../protocol';
5
- export declare class LikeC4ModelChanges {
6
- private services;
7
- private locator;
8
- constructor(services: LikeC4Services);
9
- applyChange(changeView: ChangeViewRequestParams): Promise<Location | null>;
10
- protected convertToTextEdit({ viewId, changes }: ChangeViewRequestParams): {
11
- doc: ParsedLikeC4LangiumDocument;
12
- ranges: Range[];
13
- edits: TextEdit[];
14
- };
15
- }
16
- //# sourceMappingURL=ModelChanges.d.ts.map
@@ -1,106 +0,0 @@
1
- import { invariant, nonexhaustive } from "@likec4/core";
2
- import { Range } from "vscode-languageserver-protocol";
3
- import { changeElementStyle } from "./changeElementStyle.js";
4
- import { changeViewLayout } from "./changeViewLayout.js";
5
- function unionRangeOfAllEdits(ranges) {
6
- let startLine = Number.MAX_SAFE_INTEGER;
7
- let endLine = Number.MIN_SAFE_INTEGER;
8
- let startCharacter = Number.MAX_SAFE_INTEGER;
9
- let endCharacter = Number.MIN_SAFE_INTEGER;
10
- for (const { start, end } of ranges) {
11
- if (start.line <= startLine) {
12
- if (startLine == start.line) {
13
- startCharacter = Math.min(start.character, startCharacter);
14
- } else {
15
- startLine = start.line;
16
- startCharacter = start.character;
17
- }
18
- }
19
- if (endLine <= end.line) {
20
- if (endLine == end.line) {
21
- endCharacter = Math.max(end.character, endCharacter);
22
- } else {
23
- endLine = end.line;
24
- endCharacter = end.character;
25
- }
26
- }
27
- }
28
- return Range.create(startLine, startCharacter, endLine, endCharacter);
29
- }
30
- export class LikeC4ModelChanges {
31
- constructor(services) {
32
- this.services = services;
33
- this.locator = services.likec4.ModelLocator;
34
- }
35
- locator;
36
- async applyChange(changeView) {
37
- const lspConnection = this.services.shared.lsp.Connection;
38
- invariant(lspConnection, "LSP Connection not available");
39
- let result = null;
40
- await this.services.shared.workspace.WorkspaceLock.write(async () => {
41
- const { doc, edits } = this.convertToTextEdit(changeView);
42
- const textDocument = {
43
- uri: doc.textDocument.uri,
44
- version: doc.textDocument.version
45
- };
46
- if (!edits.length) {
47
- return;
48
- }
49
- const applyResult = await lspConnection.workspace.applyEdit({
50
- label: `LikeC4 - change view ${changeView.viewId}`,
51
- edit: {
52
- changes: {
53
- [textDocument.uri]: edits
54
- }
55
- }
56
- });
57
- if (!applyResult.applied) {
58
- lspConnection.window.showErrorMessage(`Failed to apply changes ${applyResult.failureReason}`);
59
- return;
60
- }
61
- result = {
62
- uri: textDocument.uri,
63
- range: unionRangeOfAllEdits(edits.map((edit) => edit.range))
64
- };
65
- });
66
- return result;
67
- }
68
- convertToTextEdit({ viewId, changes }) {
69
- const lookup = this.locator.locateViewAst(viewId);
70
- if (!lookup) {
71
- throw new Error(`View not found: ${viewId}`);
72
- }
73
- const ranges = [];
74
- const edits = [];
75
- for (const change of changes) {
76
- switch (change.op) {
77
- case "change-element-style": {
78
- const { edits: elementEdits, modifiedRange } = changeElementStyle(this.services, {
79
- ...lookup,
80
- targets: change.targets,
81
- style: change.style
82
- });
83
- ranges.push(modifiedRange);
84
- edits.push(...elementEdits);
85
- break;
86
- }
87
- case "change-autolayout": {
88
- const edit = changeViewLayout(this.services, {
89
- ...lookup,
90
- layout: change.layout
91
- });
92
- edits.push(edit);
93
- ranges.push(edit.range);
94
- break;
95
- }
96
- default:
97
- nonexhaustive(change);
98
- }
99
- }
100
- return {
101
- doc: lookup.doc,
102
- ranges,
103
- edits
104
- };
105
- }
106
- }
@@ -1,18 +0,0 @@
1
- import { type Fqn, type NonEmptyArray } from '@likec4/core';
2
- import { type Range, TextEdit } from 'vscode-languageserver-protocol';
3
- import { ast, type ParsedAstView, type ParsedLikeC4LangiumDocument } from '../ast';
4
- import type { LikeC4Services } from '../module';
5
- import type { ChangeView } from '../protocol';
6
- type ChangeElementStyleArg = {
7
- view: ParsedAstView;
8
- doc: ParsedLikeC4LangiumDocument;
9
- viewAst: ast.LikeC4View;
10
- targets: NonEmptyArray<Fqn>;
11
- style: ChangeView.ChangeElementStyle['style'];
12
- };
13
- export declare function changeElementStyle(services: LikeC4Services, { view, viewAst, targets, style }: ChangeElementStyleArg): {
14
- modifiedRange: Range;
15
- edits: TextEdit[];
16
- };
17
- export {};
18
- //# sourceMappingURL=changeElementStyle.d.ts.map