@likec4/language-server 1.17.1 → 1.19.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 (268) hide show
  1. package/contrib/likec4.tmLanguage.json +1 -1
  2. package/dist/LikeC4FileSystem.d.ts +13 -0
  3. package/dist/LikeC4FileSystem.js +27 -0
  4. package/dist/Rpc.d.ts +9 -0
  5. package/dist/Rpc.js +126 -0
  6. package/dist/ast.d.ts +200 -0
  7. package/dist/ast.js +276 -0
  8. package/dist/browser.d.ts +6 -20
  9. package/dist/browser.js +13 -0
  10. package/dist/formatting/LikeC4Formatter.d.ts +27 -0
  11. package/dist/formatting/LikeC4Formatter.js +261 -0
  12. package/dist/formatting/utils.d.ts +6 -0
  13. package/dist/formatting/utils.js +15 -0
  14. package/dist/generated/ast.d.ts +1242 -0
  15. package/dist/generated/ast.js +1945 -0
  16. package/dist/generated/grammar.d.ts +6 -0
  17. package/dist/generated/grammar.js +3 -0
  18. package/dist/generated/module.d.ts +9 -0
  19. package/dist/generated/module.js +23 -0
  20. package/dist/generated-lib/icons.d.ts +1 -0
  21. package/dist/{likec4lib.mjs → generated-lib/icons.js} +1 -6
  22. package/dist/index.d.ts +8 -31
  23. package/dist/index.js +13 -0
  24. package/dist/like-c4.langium +845 -0
  25. package/dist/likec4lib.d.ts +4 -6
  26. package/dist/likec4lib.js +4 -0
  27. package/dist/logger.d.ts +7 -0
  28. package/dist/logger.js +73 -0
  29. package/dist/lsp/CodeLensProvider.d.ts +9 -0
  30. package/dist/lsp/CodeLensProvider.js +40 -0
  31. package/dist/lsp/CompletionProvider.d.ts +6 -0
  32. package/dist/lsp/CompletionProvider.js +135 -0
  33. package/dist/lsp/DocumentHighlightProvider.d.ts +9 -0
  34. package/dist/lsp/DocumentHighlightProvider.js +10 -0
  35. package/dist/lsp/DocumentLinkProvider.d.ts +11 -0
  36. package/dist/lsp/DocumentLinkProvider.js +49 -0
  37. package/dist/lsp/DocumentSymbolProvider.d.ts +23 -0
  38. package/dist/lsp/DocumentSymbolProvider.js +202 -0
  39. package/dist/lsp/HoverProvider.d.ts +10 -0
  40. package/dist/lsp/HoverProvider.js +69 -0
  41. package/dist/lsp/RenameProvider.d.ts +5 -0
  42. package/dist/lsp/RenameProvider.js +6 -0
  43. package/dist/lsp/SemanticTokenProvider.d.ts +7 -0
  44. package/dist/lsp/SemanticTokenProvider.js +297 -0
  45. package/dist/lsp/index.d.ts +7 -0
  46. package/dist/lsp/index.js +7 -0
  47. package/dist/model/deployments-index.d.ts +60 -0
  48. package/dist/model/deployments-index.js +181 -0
  49. package/dist/model/fqn-computation.d.ts +3 -0
  50. package/dist/model/fqn-computation.js +72 -0
  51. package/dist/model/fqn-index.d.ts +25 -0
  52. package/dist/model/fqn-index.js +96 -0
  53. package/dist/model/index.d.ts +6 -0
  54. package/dist/model/index.js +6 -0
  55. package/dist/model/model-builder.d.ts +32 -0
  56. package/dist/model/model-builder.js +598 -0
  57. package/dist/model/model-locator.d.ts +23 -0
  58. package/dist/model/model-locator.js +126 -0
  59. package/dist/model/model-parser-where.d.ts +3 -0
  60. package/dist/model/model-parser-where.js +70 -0
  61. package/dist/model/model-parser.d.ts +292 -0
  62. package/dist/model/model-parser.js +72 -0
  63. package/dist/model/parser/Base.d.ts +28 -0
  64. package/dist/model/parser/Base.js +87 -0
  65. package/dist/model/parser/DeploymentModelParser.d.ts +33 -0
  66. package/dist/model/parser/DeploymentModelParser.js +162 -0
  67. package/dist/model/parser/DeploymentViewParser.d.ts +38 -0
  68. package/dist/model/parser/DeploymentViewParser.js +98 -0
  69. package/dist/model/parser/FqnRefParser.d.ts +29 -0
  70. package/dist/model/parser/FqnRefParser.js +108 -0
  71. package/dist/model/parser/GlobalsParser.d.ts +66 -0
  72. package/dist/model/parser/GlobalsParser.js +80 -0
  73. package/dist/model/parser/ModelParser.d.ts +27 -0
  74. package/dist/model/parser/ModelParser.js +122 -0
  75. package/dist/model/parser/PredicatesParser.d.ts +34 -0
  76. package/dist/model/parser/PredicatesParser.js +272 -0
  77. package/dist/model/parser/SpecificationParser.d.ts +27 -0
  78. package/dist/model/parser/SpecificationParser.js +120 -0
  79. package/dist/model/parser/ViewsParser.d.ts +64 -0
  80. package/dist/model/parser/ViewsParser.js +377 -0
  81. package/dist/model-change/ModelChanges.d.ts +15 -0
  82. package/dist/model-change/ModelChanges.js +89 -0
  83. package/dist/model-change/changeElementStyle.d.ts +16 -0
  84. package/dist/model-change/changeElementStyle.js +136 -0
  85. package/dist/model-change/changeViewLayout.d.ts +12 -0
  86. package/dist/model-change/changeViewLayout.js +32 -0
  87. package/dist/model-change/saveManualLayout.d.ts +11 -0
  88. package/dist/model-change/saveManualLayout.js +27 -0
  89. package/dist/module.d.ts +62 -0
  90. package/dist/module.js +123 -0
  91. package/dist/protocol.d.ts +27 -27
  92. package/dist/protocol.js +14 -0
  93. package/dist/references/index.d.ts +3 -0
  94. package/dist/references/index.js +3 -0
  95. package/dist/references/name-provider.d.ts +9 -0
  96. package/dist/references/name-provider.js +33 -0
  97. package/dist/references/scope-computation.d.ts +20 -0
  98. package/dist/references/scope-computation.js +281 -0
  99. package/dist/references/scope-provider.d.ts +16 -0
  100. package/dist/references/scope-provider.js +165 -0
  101. package/dist/shared/NodeKindProvider.d.ts +15 -0
  102. package/dist/shared/NodeKindProvider.js +108 -0
  103. package/dist/shared/WorkspaceManager.d.ts +18 -0
  104. package/dist/shared/WorkspaceManager.js +36 -0
  105. package/dist/shared/WorkspaceSymbolProvider.d.ts +3 -0
  106. package/dist/shared/WorkspaceSymbolProvider.js +3 -0
  107. package/dist/shared/index.d.ts +3 -0
  108. package/dist/shared/index.js +3 -0
  109. package/dist/test/index.d.ts +1 -0
  110. package/dist/test/index.js +1 -0
  111. package/dist/test/setup.d.ts +1 -0
  112. package/dist/test/setup.js +7 -0
  113. package/dist/test/testServices.d.ts +22 -0
  114. package/dist/test/testServices.js +119 -0
  115. package/dist/utils/elementRef.d.ts +11 -0
  116. package/dist/utils/elementRef.js +15 -0
  117. package/dist/utils/fqnRef.d.ts +8 -0
  118. package/dist/utils/fqnRef.js +46 -0
  119. package/dist/utils/index.d.ts +1 -0
  120. package/dist/utils/index.js +1 -0
  121. package/dist/utils/printDocs.d.ts +2 -0
  122. package/dist/utils/printDocs.js +1 -0
  123. package/dist/utils/stringHash.d.ts +1 -0
  124. package/dist/utils/stringHash.js +5 -0
  125. package/dist/validation/_shared.d.ts +3 -0
  126. package/dist/validation/_shared.js +22 -0
  127. package/dist/validation/deployment-checks.d.ts +6 -0
  128. package/dist/validation/deployment-checks.js +114 -0
  129. package/dist/validation/dynamic-view-rule.d.ts +4 -0
  130. package/dist/validation/dynamic-view-rule.js +16 -0
  131. package/dist/validation/dynamic-view-step.d.ts +4 -0
  132. package/dist/validation/dynamic-view-step.js +33 -0
  133. package/dist/validation/element.d.ts +4 -0
  134. package/dist/validation/element.js +49 -0
  135. package/dist/validation/index.d.ts +15 -0
  136. package/dist/validation/index.js +152 -0
  137. package/dist/validation/property-checks.d.ts +6 -0
  138. package/dist/validation/property-checks.js +38 -0
  139. package/dist/validation/relation.d.ts +5 -0
  140. package/dist/validation/relation.js +56 -0
  141. package/dist/validation/specification.d.ts +11 -0
  142. package/dist/validation/specification.js +136 -0
  143. package/dist/validation/view-predicates/element-with.d.ts +4 -0
  144. package/dist/validation/view-predicates/element-with.js +30 -0
  145. package/dist/validation/view-predicates/expanded-element.d.ts +4 -0
  146. package/dist/validation/view-predicates/expanded-element.js +11 -0
  147. package/dist/validation/view-predicates/expression-v2.d.ts +5 -0
  148. package/dist/validation/view-predicates/expression-v2.js +83 -0
  149. package/dist/validation/view-predicates/incoming.d.ts +4 -0
  150. package/dist/validation/view-predicates/incoming.js +15 -0
  151. package/dist/validation/view-predicates/index.d.ts +6 -0
  152. package/dist/validation/view-predicates/index.js +6 -0
  153. package/dist/validation/view-predicates/outgoing.d.ts +4 -0
  154. package/dist/validation/view-predicates/outgoing.js +15 -0
  155. package/dist/validation/view-predicates/relation-with.d.ts +4 -0
  156. package/dist/validation/view-predicates/relation-with.js +12 -0
  157. package/dist/validation/view.d.ts +4 -0
  158. package/dist/validation/view.js +23 -0
  159. package/dist/view-utils/assignNavigateTo.d.ts +2 -0
  160. package/dist/view-utils/assignNavigateTo.js +25 -0
  161. package/dist/view-utils/index.d.ts +2 -0
  162. package/dist/view-utils/index.js +2 -0
  163. package/dist/view-utils/manual-layout.d.ts +7 -0
  164. package/dist/view-utils/manual-layout.js +99 -0
  165. package/dist/view-utils/resolve-relative-paths.d.ts +2 -0
  166. package/dist/view-utils/resolve-relative-paths.js +78 -0
  167. package/package.json +42 -73
  168. package/src/LikeC4FileSystem.ts +22 -21
  169. package/src/Rpc.ts +6 -3
  170. package/src/ast.ts +136 -172
  171. package/src/browser.ts +10 -11
  172. package/src/generated/ast.ts +656 -40
  173. package/src/generated/grammar.ts +1 -1
  174. package/src/index.ts +11 -8
  175. package/src/like-c4.langium +173 -22
  176. package/src/logger.ts +41 -57
  177. package/src/lsp/CodeLensProvider.ts +0 -1
  178. package/src/lsp/CompletionProvider.ts +20 -5
  179. package/src/lsp/DocumentSymbolProvider.ts +5 -2
  180. package/src/lsp/HoverProvider.ts +37 -3
  181. package/src/lsp/SemanticTokenProvider.ts +58 -32
  182. package/src/model/deployments-index.ts +222 -0
  183. package/src/model/fqn-computation.ts +1 -1
  184. package/src/model/fqn-index.ts +0 -1
  185. package/src/model/index.ts +1 -0
  186. package/src/model/model-builder.ts +176 -39
  187. package/src/model/model-locator.ts +36 -7
  188. package/src/model/model-parser.ts +69 -1119
  189. package/src/model/parser/Base.ts +107 -0
  190. package/src/model/parser/DeploymentModelParser.ts +192 -0
  191. package/src/model/parser/DeploymentViewParser.ts +116 -0
  192. package/src/model/parser/FqnRefParser.ts +118 -0
  193. package/src/model/parser/GlobalsParser.ts +96 -0
  194. package/src/model/parser/ModelParser.ts +141 -0
  195. package/src/model/parser/PredicatesParser.ts +291 -0
  196. package/src/model/parser/SpecificationParser.ts +133 -0
  197. package/src/model/parser/ViewsParser.ts +428 -0
  198. package/src/model-change/changeViewLayout.ts +2 -2
  199. package/src/module.ts +26 -21
  200. package/src/protocol.ts +10 -6
  201. package/src/references/index.ts +1 -0
  202. package/src/references/name-provider.ts +37 -0
  203. package/src/references/scope-computation.ts +130 -21
  204. package/src/references/scope-provider.ts +68 -35
  205. package/src/shared/NodeKindProvider.ts +15 -3
  206. package/src/{elementRef.ts → utils/elementRef.ts} +1 -1
  207. package/src/utils/fqnRef.ts +56 -0
  208. package/src/utils/stringHash.ts +2 -2
  209. package/src/validation/_shared.ts +6 -5
  210. package/src/validation/deployment-checks.ts +131 -0
  211. package/src/validation/dynamic-view-step.ts +1 -1
  212. package/src/validation/index.ts +104 -6
  213. package/src/validation/relation.ts +1 -1
  214. package/src/validation/view-predicates/expression-v2.ts +101 -0
  215. package/src/validation/view-predicates/index.ts +1 -0
  216. package/src/view-utils/assignNavigateTo.ts +6 -5
  217. package/src/view-utils/index.ts +0 -1
  218. package/src/view-utils/manual-layout.ts +25 -0
  219. package/dist/browser.cjs +0 -25
  220. package/dist/browser.d.cts +0 -23
  221. package/dist/browser.d.mts +0 -23
  222. package/dist/browser.mjs +0 -20
  223. package/dist/index.cjs +0 -53
  224. package/dist/index.d.cts +0 -34
  225. package/dist/index.d.mts +0 -34
  226. package/dist/index.mjs +0 -46
  227. package/dist/likec4lib.cjs +0 -1546
  228. package/dist/likec4lib.d.cts +0 -6
  229. package/dist/likec4lib.d.mts +0 -6
  230. package/dist/model-graph/index.cjs +0 -10
  231. package/dist/model-graph/index.d.cts +0 -81
  232. package/dist/model-graph/index.d.mts +0 -81
  233. package/dist/model-graph/index.d.ts +0 -81
  234. package/dist/model-graph/index.mjs +0 -1
  235. package/dist/protocol.cjs +0 -25
  236. package/dist/protocol.d.cts +0 -45
  237. package/dist/protocol.d.mts +0 -45
  238. package/dist/protocol.mjs +0 -17
  239. package/dist/shared/language-server.BIbAD1T-.mjs +0 -6292
  240. package/dist/shared/language-server.BQRvVmE0.d.cts +0 -1303
  241. package/dist/shared/language-server.BysPcTxr.d.ts +0 -1303
  242. package/dist/shared/language-server.D2QdbOJO.cjs +0 -1995
  243. package/dist/shared/language-server.DGrBGmsd.mjs +0 -1981
  244. package/dist/shared/language-server.DKV_FdPN.cjs +0 -6304
  245. package/dist/shared/language-server._wkyPgso.d.mts +0 -1303
  246. package/src/model-graph/LikeC4ModelGraph.ts +0 -338
  247. package/src/model-graph/compute-view/__test__/fixture.ts +0 -630
  248. package/src/model-graph/compute-view/compute.ts +0 -788
  249. package/src/model-graph/compute-view/index.ts +0 -33
  250. package/src/model-graph/compute-view/predicates.ts +0 -509
  251. package/src/model-graph/dynamic-view/__test__/fixture.ts +0 -61
  252. package/src/model-graph/dynamic-view/compute.ts +0 -313
  253. package/src/model-graph/dynamic-view/index.ts +0 -29
  254. package/src/model-graph/index.ts +0 -3
  255. package/src/model-graph/utils/applyCustomElementProperties.ts +0 -65
  256. package/src/model-graph/utils/applyCustomRelationProperties.ts +0 -41
  257. package/src/model-graph/utils/applyViewRuleStyles.ts +0 -49
  258. package/src/model-graph/utils/buildComputeNodes.ts +0 -113
  259. package/src/model-graph/utils/buildElementNotations.ts +0 -63
  260. package/src/model-graph/utils/elementExpressionToPredicate.ts +0 -39
  261. package/src/model-graph/utils/relationExpressionToPredicates.ts +0 -43
  262. package/src/model-graph/utils/sortNodes.ts +0 -105
  263. package/src/model-graph/utils/uniqueTags.test.ts +0 -42
  264. package/src/model-graph/utils/uniqueTags.ts +0 -19
  265. package/src/utils/graphlib.ts +0 -9
  266. package/src/view-utils/resolve-extended-views.ts +0 -66
  267. package/src/view-utils/resolve-global-rules.ts +0 -88
  268. package/src/view-utils/view-hash.ts +0 -27
@@ -0,0 +1,64 @@
1
+ import type * as c4 from '@likec4/core';
2
+ import { ast, type ParsedAstDynamicView, type ParsedAstElementView } from '../../ast';
3
+ import type { NotationProperty } from '../../generated/ast';
4
+ import type { WithDeploymentView } from './DeploymentViewParser';
5
+ import type { WithPredicates } from './PredicatesParser';
6
+ export type WithViewsParser = ReturnType<typeof ViewsParser>;
7
+ export declare function ViewsParser<TBase extends WithPredicates & WithDeploymentView>(B: TBase): {
8
+ new (...args: any[]): {
9
+ parseViews(): void;
10
+ parseElementView(astNode: ast.ElementView, additionalStyles: c4.ViewRuleStyleOrGlobalRef[]): ParsedAstElementView;
11
+ parseViewRule(astRule: ast.ViewRule): c4.ViewRule;
12
+ parseViewRulePredicate(astNode: ast.ViewRulePredicate): c4.ViewRulePredicate;
13
+ parseViewRuleGlobalPredicateRef(astRule: ast.ViewRuleGlobalPredicateRef | ast.DynamicViewGlobalPredicateRef): c4.ViewRuleGlobalPredicateRef;
14
+ parseViewRuleStyleOrGlobalRef(astRule: ast.ViewRuleStyleOrGlobalRef): c4.ViewRuleStyleOrGlobalRef;
15
+ parseViewRuleGroup(astNode: ast.ViewRuleGroup): c4.ViewRuleGroup;
16
+ parseViewRuleStyle(astRule: ast.ViewRuleStyle | ast.GlobalStyle): c4.ViewRuleStyle;
17
+ parseRuleStyle(styleProperties: ast.StyleProperty[], elementExpressionsIterator: ast.ElementExpressionsIterator, notationProperty?: NotationProperty): c4.ViewRuleStyle;
18
+ parseViewRuleGlobalStyle(astRule: ast.ViewRuleGlobalStyle): c4.ViewRuleGlobalStyle;
19
+ parseDynamicElementView(astNode: ast.DynamicView, additionalStyles: c4.ViewRuleStyleOrGlobalRef[]): ParsedAstDynamicView;
20
+ parseDynamicViewRule(astRule: ast.DynamicViewRule): c4.DynamicViewRule;
21
+ parseDynamicViewIncludePredicate(astRule: ast.DynamicViewIncludePredicate): c4.DynamicViewIncludeRule;
22
+ parseDynamicParallelSteps(node: ast.DynamicViewParallelSteps): c4.DynamicViewParallelSteps;
23
+ parseDynamicStep(node: ast.DynamicViewStep): c4.DynamicViewStep;
24
+ parsePredicate(astNode: ast.Predicate): c4.Expression;
25
+ parseElementPredicate(astNode: ast.ElementPredicate): c4.ElementPredicateExpression;
26
+ parseElementExpressionsIterator(astNode: ast.ElementExpressionsIterator): c4.ElementExpression[];
27
+ parseElementExpression(astNode: ast.ElementExpression): c4.ElementExpression;
28
+ parseElementPredicateWhere(astNode: ast.ElementPredicateWhere): c4.ElementWhereExpr;
29
+ parseElementPredicateWith(astNode: ast.ElementPredicateWith): c4.CustomElementExpr;
30
+ parseRelationPredicate(astNode: ast.RelationPredicate): c4.RelationPredicateExpression;
31
+ parseRelationPredicateWhere(astNode: ast.RelationPredicateWhere): c4.RelationWhereExpr;
32
+ parseRelationPredicateWith(astNode: ast.RelationPredicateWith, relation: c4.RelationExpression | c4.RelationWhereExpr): c4.CustomRelationExpr;
33
+ parseRelationExpression(astNode: ast.RelationExpression): c4.RelationExpression;
34
+ isValid: import("../../validation").IsValidFn;
35
+ readonly services: import("../..").LikeC4Services;
36
+ readonly doc: import("../../ast").ParsedLikeC4LangiumDocument;
37
+ resolveFqn(node: ast.FqnReferenceable): c4.Fqn;
38
+ getAstNodePath(node: c4): any;
39
+ getMetadata(metadataAstNode: ast.MetadataProperty | undefined): {
40
+ [key: string]: string;
41
+ } | undefined;
42
+ convertTags<E extends {
43
+ tags?: ast.Tags;
44
+ }>(withTags?: E | undefined): any;
45
+ parseTags<E extends {
46
+ tags?: ast.Tags;
47
+ }>(withTags?: E): c4.NonEmptyArray<c4.Tag> | null;
48
+ convertLinks(source?: ast.LinkProperty["$container"]): import("../../ast").ParsedLink[] | undefined;
49
+ parseLinks(source?: ast.LinkProperty["$container"]): import("../../ast").ParsedLink[] | undefined;
50
+ parseDeploymentView(astNode: ast.DeploymentView): import("../../ast").ParsedAstDeploymentView;
51
+ parseDeploymentViewRule(astRule: ast.DeploymentViewRule): c4.DeploymentViewRule;
52
+ parseDeploymentViewRulePredicate(astRule: ast.DeploymentViewRulePredicate): c4.DeploymentViewRulePredicate;
53
+ parseDeploymentViewRuleStyle(astRule: ast.DeploymentViewRuleStyle): c4.DeploymentViewRuleStyle;
54
+ parseFqnRef(astNode: ast.FqnRef): c4.FqnRef;
55
+ parseFqnExpr(astNode: ast.FqnExpr): c4.FqnExpr;
56
+ parseFqnRefExpr(astNode: ast.FqnRefExpr): c4.FqnExpr.NonWildcard;
57
+ parseFqnExpressions(astNode: ast.FqnExpressions): c4.FqnExpr[];
58
+ parseRelationExpr(astNode: ast.RelationExpr): c4.RelationExpr;
59
+ parseDeployment(): void;
60
+ parseDeploymentNode(astNode: ast.DeploymentNode): import("../../ast").ParsedAstDeployment.Node;
61
+ parseDeployedInstance(astNode: ast.DeployedInstance): import("../../ast").ParsedAstDeployment.Instance;
62
+ parseDeploymentRelation(astNode: ast.DeploymentRelation): import("../../ast").ParsedAstDeploymentRelation;
63
+ };
64
+ } & TBase;
@@ -0,0 +1,377 @@
1
+ import { invariant, isNonEmptyArray, nonexhaustive } from "@likec4/core";
2
+ import { isArray, isDefined, isNonNullish, isTruthy } from "remeda";
3
+ import {
4
+ ast,
5
+ toAutoLayout,
6
+ toColor,
7
+ toElementStyle,
8
+ ViewOps
9
+ } from "../../ast.js";
10
+ import { logger, logWarnError } from "../../logger.js";
11
+ import { stringHash } from "../../utils/index.js";
12
+ import { elementRef } from "../../utils/elementRef.js";
13
+ import { parseViewManualLayout } from "../../view-utils/manual-layout.js";
14
+ import { removeIndent, toSingleLine } from "./Base.js";
15
+ export function ViewsParser(B) {
16
+ return class ViewsParser extends B {
17
+ parseViews() {
18
+ const isValid = this.isValid;
19
+ for (const viewBlock of this.doc.parseResult.value.views) {
20
+ const localStyles = viewBlock.styles.flatMap((s) => {
21
+ try {
22
+ return isValid(s) ? this.parseViewRuleStyleOrGlobalRef(s) : [];
23
+ } catch (e) {
24
+ logWarnError(e);
25
+ return [];
26
+ }
27
+ });
28
+ for (const view of viewBlock.views) {
29
+ try {
30
+ if (!isValid(view)) {
31
+ continue;
32
+ }
33
+ switch (true) {
34
+ case ast.isElementView(view):
35
+ this.doc.c4Views.push(this.parseElementView(view, localStyles));
36
+ break;
37
+ case ast.isDynamicView(view):
38
+ this.doc.c4Views.push(this.parseDynamicElementView(view, localStyles));
39
+ break;
40
+ case ast.isDeploymentView(view):
41
+ this.doc.c4Views.push(this.parseDeploymentView(view));
42
+ break;
43
+ default:
44
+ nonexhaustive(view);
45
+ }
46
+ } catch (e) {
47
+ logWarnError(e);
48
+ }
49
+ }
50
+ }
51
+ }
52
+ parseElementView(astNode, additionalStyles) {
53
+ const body = astNode.body;
54
+ invariant(body, "ElementView body is not defined");
55
+ const astPath = this.getAstNodePath(astNode);
56
+ let viewOf = null;
57
+ if ("viewOf" in astNode) {
58
+ const viewOfEl = elementRef(astNode.viewOf);
59
+ const _viewOf = viewOfEl && this.resolveFqn(viewOfEl);
60
+ if (!_viewOf) {
61
+ logger.warn("viewOf is not resolved: " + astNode.$cstNode?.text);
62
+ } else {
63
+ viewOf = _viewOf;
64
+ }
65
+ }
66
+ let id = astNode.name;
67
+ if (!id) {
68
+ id = "view_" + stringHash(
69
+ this.doc.uri.toString(),
70
+ astPath,
71
+ viewOf ?? ""
72
+ );
73
+ }
74
+ const title = toSingleLine(body.props.find((p) => p.key === "title")?.value) ?? null;
75
+ const description = removeIndent(body.props.find((p) => p.key === "description")?.value) ?? null;
76
+ const tags = this.convertTags(body);
77
+ const links = this.convertLinks(body);
78
+ const manualLayout = parseViewManualLayout(astNode);
79
+ const view = {
80
+ __: "element",
81
+ id,
82
+ astPath,
83
+ title,
84
+ description,
85
+ tags,
86
+ links: isNonEmptyArray(links) ? links : null,
87
+ rules: [
88
+ ...additionalStyles,
89
+ ...body.rules.flatMap((n) => {
90
+ try {
91
+ return this.isValid(n) ? this.parseViewRule(n) : [];
92
+ } catch (e) {
93
+ logWarnError(e);
94
+ return [];
95
+ }
96
+ })
97
+ ],
98
+ ...viewOf && { viewOf },
99
+ ...manualLayout && { manualLayout }
100
+ };
101
+ ViewOps.writeId(astNode, view.id);
102
+ if ("extends" in astNode) {
103
+ const extendsView = astNode.extends.view.ref;
104
+ invariant(extendsView?.name, "view extends is not resolved: " + astNode.$cstNode?.text);
105
+ return Object.assign(view, {
106
+ extends: extendsView.name
107
+ });
108
+ }
109
+ return view;
110
+ }
111
+ parseViewRule(astRule) {
112
+ if (ast.isViewRulePredicate(astRule)) {
113
+ return this.parseViewRulePredicate(astRule);
114
+ }
115
+ if (ast.isViewRuleGlobalPredicateRef(astRule)) {
116
+ return this.parseViewRuleGlobalPredicateRef(astRule);
117
+ }
118
+ if (ast.isViewRuleStyleOrGlobalRef(astRule)) {
119
+ return this.parseViewRuleStyleOrGlobalRef(astRule);
120
+ }
121
+ if (ast.isViewRuleAutoLayout(astRule)) {
122
+ return toAutoLayout(astRule);
123
+ }
124
+ if (ast.isViewRuleGroup(astRule)) {
125
+ return this.parseViewRuleGroup(astRule);
126
+ }
127
+ nonexhaustive(astRule);
128
+ }
129
+ parseViewRulePredicate(astNode) {
130
+ const exprs = [];
131
+ let predicate = astNode.predicates;
132
+ while (predicate) {
133
+ const { value, prev } = predicate;
134
+ try {
135
+ if (isTruthy(value) && this.isValid(value)) {
136
+ exprs.unshift(this.parsePredicate(value));
137
+ }
138
+ } catch (e) {
139
+ logWarnError(e);
140
+ }
141
+ if (!prev) {
142
+ break;
143
+ }
144
+ predicate = prev;
145
+ }
146
+ return ast.isIncludePredicate(astNode) ? { include: exprs } : { exclude: exprs };
147
+ }
148
+ parseViewRuleGlobalPredicateRef(astRule) {
149
+ return {
150
+ predicateId: astRule.predicate.$refText
151
+ };
152
+ }
153
+ parseViewRuleStyleOrGlobalRef(astRule) {
154
+ if (ast.isViewRuleStyle(astRule)) {
155
+ return this.parseViewRuleStyle(astRule);
156
+ }
157
+ if (ast.isViewRuleGlobalStyle(astRule)) {
158
+ return this.parseViewRuleGlobalStyle(astRule);
159
+ }
160
+ nonexhaustive(astRule);
161
+ }
162
+ parseViewRuleGroup(astNode) {
163
+ const groupRules = [];
164
+ for (const rule of astNode.groupRules) {
165
+ try {
166
+ if (!this.isValid(rule)) {
167
+ continue;
168
+ }
169
+ if (ast.isViewRulePredicate(rule)) {
170
+ groupRules.push(this.parseViewRulePredicate(rule));
171
+ continue;
172
+ }
173
+ if (ast.isViewRuleGroup(rule)) {
174
+ groupRules.push(this.parseViewRuleGroup(rule));
175
+ continue;
176
+ }
177
+ nonexhaustive(rule);
178
+ } catch (e) {
179
+ logWarnError(e);
180
+ }
181
+ }
182
+ return {
183
+ title: toSingleLine(astNode.title) ?? null,
184
+ groupRules,
185
+ ...toElementStyle(astNode.props, this.isValid)
186
+ };
187
+ }
188
+ parseViewRuleStyle(astRule) {
189
+ const styleProps = astRule.props.filter(ast.isStyleProperty);
190
+ const targets = astRule.target;
191
+ const notation = astRule.props.find(ast.isNotationProperty);
192
+ return this.parseRuleStyle(styleProps, targets, notation);
193
+ }
194
+ parseRuleStyle(styleProperties, elementExpressionsIterator, notationProperty) {
195
+ const styleProps = toElementStyle(styleProperties, this.isValid);
196
+ const notation = removeIndent(notationProperty?.value);
197
+ const targets = this.parseElementExpressionsIterator(elementExpressionsIterator);
198
+ return {
199
+ targets,
200
+ ...notation && { notation },
201
+ style: {
202
+ ...styleProps
203
+ }
204
+ };
205
+ }
206
+ parseViewRuleGlobalStyle(astRule) {
207
+ return {
208
+ styleId: astRule.style.$refText
209
+ };
210
+ }
211
+ parseDynamicElementView(astNode, additionalStyles) {
212
+ const body = astNode.body;
213
+ invariant(body, "DynamicElementView body is not defined");
214
+ const isValid = this.isValid;
215
+ const props = body.props.filter(isValid);
216
+ const astPath = this.getAstNodePath(astNode);
217
+ let id = astNode.name;
218
+ if (!id) {
219
+ id = "dynamic_" + stringHash(
220
+ this.doc.uri.toString(),
221
+ astPath
222
+ );
223
+ }
224
+ const title = toSingleLine(props.find((p) => p.key === "title")?.value) ?? null;
225
+ const description = removeIndent(props.find((p) => p.key === "description")?.value) ?? null;
226
+ const tags = this.convertTags(body);
227
+ const links = this.convertLinks(body);
228
+ ViewOps.writeId(astNode, id);
229
+ const manualLayout = parseViewManualLayout(astNode);
230
+ return {
231
+ __: "dynamic",
232
+ id,
233
+ astPath,
234
+ title,
235
+ description,
236
+ tags,
237
+ links: isNonEmptyArray(links) ? links : null,
238
+ rules: [
239
+ ...additionalStyles,
240
+ ...body.rules.flatMap((n) => {
241
+ try {
242
+ return isValid(n) ? this.parseDynamicViewRule(n) : [];
243
+ } catch (e) {
244
+ logWarnError(e);
245
+ return [];
246
+ }
247
+ }, [])
248
+ ],
249
+ steps: body.steps.reduce((acc, n) => {
250
+ try {
251
+ if (isValid(n)) {
252
+ if (ast.isDynamicViewParallelSteps(n)) {
253
+ acc.push(this.parseDynamicParallelSteps(n));
254
+ } else {
255
+ acc.push(this.parseDynamicStep(n));
256
+ }
257
+ }
258
+ } catch (e) {
259
+ logWarnError(e);
260
+ }
261
+ return acc;
262
+ }, []),
263
+ ...manualLayout && { manualLayout }
264
+ };
265
+ }
266
+ parseDynamicViewRule(astRule) {
267
+ if (ast.isDynamicViewIncludePredicate(astRule)) {
268
+ return this.parseDynamicViewIncludePredicate(astRule);
269
+ }
270
+ if (ast.isDynamicViewGlobalPredicateRef(astRule)) {
271
+ return this.parseViewRuleGlobalPredicateRef(astRule);
272
+ }
273
+ if (ast.isViewRuleStyleOrGlobalRef(astRule)) {
274
+ return this.parseViewRuleStyleOrGlobalRef(astRule);
275
+ }
276
+ if (ast.isViewRuleAutoLayout(astRule)) {
277
+ return toAutoLayout(astRule);
278
+ }
279
+ nonexhaustive(astRule);
280
+ }
281
+ parseDynamicViewIncludePredicate(astRule) {
282
+ const include = [];
283
+ let iter = astRule.predicates;
284
+ while (iter) {
285
+ try {
286
+ if (isNonNullish(iter.value) && this.isValid(iter.value)) {
287
+ const c4expr = this.parseElementPredicate(iter.value);
288
+ include.unshift(c4expr);
289
+ }
290
+ } catch (e) {
291
+ logWarnError(e);
292
+ }
293
+ iter = iter.prev;
294
+ }
295
+ return { include };
296
+ }
297
+ parseDynamicParallelSteps(node) {
298
+ return {
299
+ __parallel: node.steps.map((step) => this.parseDynamicStep(step))
300
+ };
301
+ }
302
+ parseDynamicStep(node) {
303
+ const sourceEl = elementRef(node.source);
304
+ if (!sourceEl) {
305
+ throw new Error("Invalid reference to source");
306
+ }
307
+ const targetEl = elementRef(node.target);
308
+ if (!targetEl) {
309
+ throw new Error("Invalid reference to target");
310
+ }
311
+ let source = this.resolveFqn(sourceEl);
312
+ let target = this.resolveFqn(targetEl);
313
+ const title = removeIndent(node.title) ?? null;
314
+ let step = {
315
+ source,
316
+ target,
317
+ title
318
+ };
319
+ if (node.isBackward) {
320
+ step = {
321
+ source: target,
322
+ target: source,
323
+ title,
324
+ isBackward: true
325
+ };
326
+ }
327
+ if (!isArray(node.custom?.props)) {
328
+ return step;
329
+ }
330
+ for (const prop of node.custom.props) {
331
+ try {
332
+ switch (true) {
333
+ case ast.isRelationNavigateToProperty(prop): {
334
+ const viewId = prop.value.view.ref?.name;
335
+ if (isTruthy(viewId)) {
336
+ step.navigateTo = viewId;
337
+ }
338
+ break;
339
+ }
340
+ case ast.isRelationStringProperty(prop):
341
+ case ast.isNotationProperty(prop):
342
+ case ast.isNotesProperty(prop): {
343
+ if (isDefined(prop.value)) {
344
+ step[prop.key] = removeIndent(prop.value) ?? "";
345
+ }
346
+ break;
347
+ }
348
+ case ast.isArrowProperty(prop): {
349
+ if (isDefined(prop.value)) {
350
+ step[prop.key] = prop.value;
351
+ }
352
+ break;
353
+ }
354
+ case ast.isColorProperty(prop): {
355
+ const value = toColor(prop);
356
+ if (isDefined(value)) {
357
+ step[prop.key] = value;
358
+ }
359
+ break;
360
+ }
361
+ case ast.isLineProperty(prop): {
362
+ if (isDefined(prop.value)) {
363
+ step[prop.key] = prop.value;
364
+ }
365
+ break;
366
+ }
367
+ default:
368
+ nonexhaustive(prop);
369
+ }
370
+ } catch (e) {
371
+ logWarnError(e);
372
+ }
373
+ }
374
+ return step;
375
+ }
376
+ };
377
+ }
@@ -0,0 +1,15 @@
1
+ import { Location, Range, TextEdit } from 'vscode-languageserver-types';
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, change }: ChangeViewRequestParams): {
11
+ doc: ParsedLikeC4LangiumDocument;
12
+ modifiedRange: Range;
13
+ edits: TextEdit[];
14
+ };
15
+ }
@@ -0,0 +1,89 @@
1
+ import { invariant, nonexhaustive } from "@likec4/core";
2
+ import { logger } from "@likec4/log";
3
+ import { changeElementStyle } from "./changeElementStyle.js";
4
+ import { changeViewLayout } from "./changeViewLayout.js";
5
+ import { saveManualLayout } from "./saveManualLayout.js";
6
+ export class LikeC4ModelChanges {
7
+ constructor(services) {
8
+ this.services = services;
9
+ this.locator = services.likec4.ModelLocator;
10
+ }
11
+ locator;
12
+ async applyChange(changeView) {
13
+ const lspConnection = this.services.shared.lsp.Connection;
14
+ invariant(lspConnection, "LSP Connection not available");
15
+ let result = null;
16
+ try {
17
+ await this.services.shared.workspace.WorkspaceLock.write(async () => {
18
+ const { doc, edits, modifiedRange } = this.convertToTextEdit(changeView);
19
+ const textDocument = {
20
+ uri: doc.textDocument.uri,
21
+ version: doc.textDocument.version
22
+ };
23
+ if (!edits.length) {
24
+ return;
25
+ }
26
+ const applyResult = await lspConnection.workspace.applyEdit({
27
+ label: `LikeC4 - change view ${changeView.viewId}`,
28
+ edit: {
29
+ changes: {
30
+ [textDocument.uri]: edits
31
+ }
32
+ }
33
+ });
34
+ if (!applyResult.applied) {
35
+ lspConnection.window.showErrorMessage(`Failed to apply changes ${applyResult.failureReason}`);
36
+ return;
37
+ }
38
+ result = {
39
+ uri: textDocument.uri,
40
+ range: modifiedRange
41
+ };
42
+ });
43
+ } catch (e) {
44
+ logger.error(`Failed to apply change ${changeView.change.op} ${changeView.viewId}`, e);
45
+ }
46
+ return result;
47
+ }
48
+ convertToTextEdit({ viewId, change }) {
49
+ const lookup = this.locator.locateViewAst(viewId);
50
+ if (!lookup) {
51
+ throw new Error(`LikeC4ModelChanges: view not found: ${viewId}`);
52
+ }
53
+ switch (change.op) {
54
+ case "change-element-style": {
55
+ return {
56
+ doc: lookup.doc,
57
+ ...changeElementStyle(this.services, {
58
+ ...lookup,
59
+ targets: change.targets,
60
+ style: change.style
61
+ })
62
+ };
63
+ }
64
+ case "change-autolayout": {
65
+ const edit2 = changeViewLayout(this.services, {
66
+ ...lookup,
67
+ layout: change.layout
68
+ });
69
+ return {
70
+ doc: lookup.doc,
71
+ modifiedRange: edit2.range,
72
+ edits: [edit2]
73
+ };
74
+ }
75
+ case "save-manual-layout":
76
+ const edit = saveManualLayout(this.services, {
77
+ ...lookup,
78
+ layout: change.layout
79
+ });
80
+ return {
81
+ doc: lookup.doc,
82
+ modifiedRange: edit.range,
83
+ edits: [edit]
84
+ };
85
+ default:
86
+ nonexhaustive(change);
87
+ }
88
+ }
89
+ }
@@ -0,0 +1,16 @@
1
+ import { type Fqn, type NonEmptyArray, type ViewChange } from '@likec4/core';
2
+ import { type Range, TextEdit } from 'vscode-languageserver-types';
3
+ import { ast, type ParsedAstView, type ParsedLikeC4LangiumDocument } from '../ast';
4
+ import type { LikeC4Services } from '../module';
5
+ type ChangeElementStyleArg = {
6
+ view: ParsedAstView;
7
+ doc: ParsedLikeC4LangiumDocument;
8
+ viewAst: ast.LikeC4View;
9
+ targets: NonEmptyArray<Fqn>;
10
+ style: ViewChange.ChangeElementStyle['style'];
11
+ };
12
+ export declare function changeElementStyle(services: LikeC4Services, { view, viewAst, targets, style }: ChangeElementStyleArg): {
13
+ modifiedRange: Range;
14
+ edits: TextEdit[];
15
+ };
16
+ export {};
@@ -0,0 +1,136 @@
1
+ import { invariant, isAncestor } from "@likec4/core";
2
+ import { GrammarUtils } from "langium";
3
+ import { entries, filter, findLast, isTruthy, last } from "remeda";
4
+ import { TextEdit } from "vscode-languageserver-types";
5
+ import { ast } from "../ast.js";
6
+ const { findNodeForKeyword, findNodeForProperty } = GrammarUtils;
7
+ const asViewStyleRule = (target, style, indent = 0) => {
8
+ const indentStr = indent > 0 ? " ".repeat(indent) : "";
9
+ return [
10
+ indentStr + `style ${target} {`,
11
+ ...entries(style).map(
12
+ ([key, value]) => indentStr + ` ${key} ${key === "opacity" ? value.toString() + "%" : value}`
13
+ ),
14
+ indentStr + `}`
15
+ ];
16
+ };
17
+ const isMatchingViewRule = (fqn, index) => (rule) => {
18
+ if (!ast.isViewRuleStyle(rule)) {
19
+ return false;
20
+ }
21
+ const target = rule.target.value;
22
+ if (!target || isTruthy(rule.target.prev) || !ast.isElementRef(target)) {
23
+ return false;
24
+ }
25
+ const ref = target.el.ref;
26
+ const _fqn = ref ? index.getFqn(ref) : null;
27
+ return _fqn === fqn;
28
+ };
29
+ export function changeElementStyle(services, {
30
+ view,
31
+ viewAst,
32
+ targets,
33
+ style
34
+ }) {
35
+ invariant(viewAst.body, `View ${view.id} has no body`);
36
+ const viewCstNode = viewAst.$cstNode;
37
+ invariant(viewCstNode, "viewCstNode");
38
+ const insertPos = last(viewAst.body.rules)?.$cstNode?.range.end ?? viewAst.body.$cstNode?.range.end;
39
+ invariant(insertPos, "insertPos is not defined");
40
+ const indent = viewCstNode.range.start.character + 2;
41
+ const fqnIndex = services.likec4.FqnIndex;
42
+ const styleRules = filter(viewAst.body.rules, ast.isViewRuleStyle);
43
+ const viewOf = view.__ === "element" ? view.viewOf : null;
44
+ const existing = [];
45
+ const insert = [];
46
+ targets.forEach((target) => {
47
+ const rule = findLast(styleRules, isMatchingViewRule(target, fqnIndex));
48
+ const fqn = viewOf && isAncestor(viewOf, target) ? target.substring(viewOf.length + 1) : target;
49
+ if (rule) {
50
+ existing.push({ fqn, rule });
51
+ } else {
52
+ insert.push({ fqn });
53
+ }
54
+ });
55
+ const modifiedRange = {
56
+ start: insertPos,
57
+ end: insertPos
58
+ };
59
+ const includeRange = (range) => {
60
+ if (range.start.line <= modifiedRange.start.line) {
61
+ if (range.start.line == modifiedRange.start.line) {
62
+ modifiedRange.start.character = Math.min(range.start.character, modifiedRange.start.character);
63
+ } else {
64
+ modifiedRange.start = range.start;
65
+ }
66
+ }
67
+ if (range.end.line >= modifiedRange.end.line) {
68
+ if (range.end.line == modifiedRange.end.line) {
69
+ modifiedRange.end.character = Math.max(range.end.character, modifiedRange.end.character);
70
+ } else {
71
+ modifiedRange.end = range.end;
72
+ }
73
+ }
74
+ };
75
+ const edits = [];
76
+ if (insert.length > 0) {
77
+ const linesToInsert = insert.flatMap(({ fqn }) => asViewStyleRule(fqn, style, indent));
78
+ edits.push(
79
+ TextEdit.insert(
80
+ insertPos,
81
+ "\n" + linesToInsert.join("\n")
82
+ )
83
+ );
84
+ modifiedRange.start = {
85
+ line: insertPos.line + 1,
86
+ character: indent
87
+ };
88
+ modifiedRange.end = {
89
+ line: insertPos.line + linesToInsert.length,
90
+ character: last(linesToInsert)?.length ?? 0
91
+ };
92
+ }
93
+ if (existing.length > 0) {
94
+ for (const { rule } of existing) {
95
+ const ruleCstNode = rule.$cstNode;
96
+ invariant(ruleCstNode, "RuleCstNode not found");
97
+ for (const [key, _value] of entries(style)) {
98
+ const value = key === "opacity" ? _value.toString() + "%" : _value;
99
+ const ruleProp = rule.props.find((p) => p.key === key);
100
+ if (ruleProp && ruleProp.$cstNode) {
101
+ const { range: { start, end } } = ruleProp.$cstNode;
102
+ includeRange({
103
+ start,
104
+ end
105
+ });
106
+ edits.push(TextEdit.replace({ start, end }, key + " " + value));
107
+ continue;
108
+ }
109
+ const insertPos2 = findNodeForKeyword(ruleCstNode, "{")?.range.end;
110
+ invariant(insertPos2, "Opening brace not found");
111
+ const indentStr = " ".repeat(2 + ruleCstNode.range.start.character);
112
+ const insertKeyValue = indentStr + key + " " + value;
113
+ edits.push(
114
+ TextEdit.insert(
115
+ insertPos2,
116
+ "\n" + insertKeyValue
117
+ )
118
+ );
119
+ includeRange({
120
+ start: {
121
+ line: insertPos2.line + 1,
122
+ character: indentStr.length
123
+ },
124
+ end: {
125
+ line: insertPos2.line + 1,
126
+ character: insertKeyValue.length
127
+ }
128
+ });
129
+ }
130
+ }
131
+ }
132
+ return {
133
+ modifiedRange,
134
+ edits
135
+ };
136
+ }