@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,80 @@
1
+ import { nonexhaustive } from "@likec4/core";
2
+ import { isTruthy } from "remeda";
3
+ import { ast } from "../../ast.js";
4
+ import { logger, logWarnError } from "../../logger.js";
5
+ export function GlobalsParser(B) {
6
+ return class GlobalsParser extends B {
7
+ parseGlobals() {
8
+ const { parseResult, c4Globals } = this.doc;
9
+ const isValid = this.isValid;
10
+ const globals = parseResult.value.globals.filter(isValid);
11
+ const elRelPredicates = globals.flatMap((r) => r.predicates.filter(isValid));
12
+ for (const predicate of elRelPredicates) {
13
+ try {
14
+ const globalPredicateId = predicate.name;
15
+ if (!isTruthy(globalPredicateId)) {
16
+ continue;
17
+ }
18
+ if (globalPredicateId in c4Globals.predicates) {
19
+ logger.warn(`Global predicate named "${globalPredicateId}" is already defined`);
20
+ continue;
21
+ }
22
+ this.parseAndStoreGlobalPredicateGroupOrDynamic(predicate, globalPredicateId, c4Globals);
23
+ } catch (e) {
24
+ logWarnError(e);
25
+ }
26
+ }
27
+ const styles = globals.flatMap((r) => r.styles.filter(isValid));
28
+ for (const style of styles) {
29
+ try {
30
+ const globalStyleId = style.id.name;
31
+ if (!isTruthy(globalStyleId)) {
32
+ continue;
33
+ }
34
+ if (globalStyleId in c4Globals.styles) {
35
+ logger.warn(`Global style named "${globalStyleId}" is already defined`);
36
+ continue;
37
+ }
38
+ const styles2 = this.parseGlobalStyleOrGroup(style);
39
+ if (styles2.length > 0) {
40
+ c4Globals.styles[globalStyleId] = styles2;
41
+ }
42
+ } catch (e) {
43
+ logWarnError(e);
44
+ }
45
+ }
46
+ }
47
+ parseAndStoreGlobalPredicateGroupOrDynamic(astRule, id, c4Globals) {
48
+ if (ast.isGlobalPredicateGroup(astRule)) {
49
+ const predicates = this.parseGlobalPredicateGroup(astRule);
50
+ if (predicates.length > 0) {
51
+ c4Globals.predicates[id] = predicates;
52
+ }
53
+ return;
54
+ }
55
+ if (ast.isGlobalDynamicPredicateGroup(astRule)) {
56
+ const predicates = this.parseGlobalDynamicPredicateGroup(astRule);
57
+ if (predicates.length > 0) {
58
+ c4Globals.dynamicPredicates[id] = predicates;
59
+ }
60
+ return;
61
+ }
62
+ nonexhaustive(astRule);
63
+ }
64
+ parseGlobalPredicateGroup(astRule) {
65
+ return astRule.predicates.map((p) => this.parseViewRulePredicate(p));
66
+ }
67
+ parseGlobalDynamicPredicateGroup(astRule) {
68
+ return astRule.predicates.map((p) => this.parseDynamicViewIncludePredicate(p));
69
+ }
70
+ parseGlobalStyleOrGroup(astRule) {
71
+ if (ast.isGlobalStyle(astRule)) {
72
+ return [this.parseViewRuleStyle(astRule)];
73
+ }
74
+ if (ast.isGlobalStyleGroup(astRule)) {
75
+ return astRule.styles.map((s) => this.parseViewRuleStyle(s));
76
+ }
77
+ nonexhaustive(astRule);
78
+ }
79
+ };
80
+ }
@@ -0,0 +1,27 @@
1
+ import type * as c4 from '@likec4/core';
2
+ import { type ParsedAstElement, type ParsedAstRelation, ast } from '../../ast';
3
+ import { type Base } from './Base';
4
+ export type WithModel = ReturnType<typeof ModelParser>;
5
+ export declare function ModelParser<TBase extends Base>(B: TBase): {
6
+ new (...args: any[]): {
7
+ parseModel(): void;
8
+ parseElement(astNode: ast.Element): ParsedAstElement;
9
+ parseRelation(astNode: ast.Relation): ParsedAstRelation;
10
+ isValid: import("../../validation").IsValidFn;
11
+ readonly services: import("../..").LikeC4Services;
12
+ readonly doc: import("../../ast").ParsedLikeC4LangiumDocument;
13
+ resolveFqn(node: ast.FqnReferenceable): c4.Fqn;
14
+ getAstNodePath(node: c4): any;
15
+ getMetadata(metadataAstNode: ast.MetadataProperty | undefined): {
16
+ [key: string]: string;
17
+ } | undefined;
18
+ convertTags<E extends {
19
+ tags?: ast.Tags;
20
+ }>(withTags?: E | undefined): any;
21
+ parseTags<E extends {
22
+ tags?: ast.Tags;
23
+ }>(withTags?: E): c4.NonEmptyArray<c4.Tag> | null;
24
+ convertLinks(source?: ast.LinkProperty["$container"]): import("../../ast").ParsedLink[] | undefined;
25
+ parseLinks(source?: ast.LinkProperty["$container"]): import("../../ast").ParsedLink[] | undefined;
26
+ };
27
+ } & TBase;
@@ -0,0 +1,122 @@
1
+ import { isNonEmptyArray, nonexhaustive, nonNullable } from "@likec4/core";
2
+ import { filter, first, isNonNullish, isTruthy, map, mapToObj, pipe } from "remeda";
3
+ import {
4
+ ast,
5
+ resolveRelationPoints,
6
+ streamModel,
7
+ toElementStyle,
8
+ toRelationshipStyleExcludeDefaults
9
+ } from "../../ast.js";
10
+ import { logWarnError } from "../../logger.js";
11
+ import { stringHash } from "../../utils/stringHash.js";
12
+ import { removeIndent, toSingleLine } from "./Base.js";
13
+ export function ModelParser(B) {
14
+ return class ModelParser extends B {
15
+ parseModel() {
16
+ const doc = this.doc;
17
+ for (const el of streamModel(doc)) {
18
+ try {
19
+ if (ast.isElement(el)) {
20
+ doc.c4Elements.push(this.parseElement(el));
21
+ continue;
22
+ }
23
+ if (ast.isRelation(el)) {
24
+ if (this.isValid(el)) {
25
+ doc.c4Relations.push(this.parseRelation(el));
26
+ }
27
+ continue;
28
+ }
29
+ nonexhaustive(el);
30
+ } catch (e) {
31
+ logWarnError(e);
32
+ }
33
+ }
34
+ }
35
+ parseElement(astNode) {
36
+ const isValid = this.isValid;
37
+ const id = this.resolveFqn(astNode);
38
+ const kind = nonNullable(astNode.kind.ref, "Element kind is not resolved").name;
39
+ const tags = this.parseTags(astNode.body);
40
+ const stylePropsAst = astNode.body?.props.find(ast.isElementStyleProperty)?.props;
41
+ const style = toElementStyle(stylePropsAst, isValid);
42
+ const metadata = this.getMetadata(astNode.body?.props.find(ast.isMetadataProperty));
43
+ const astPath = this.getAstNodePath(astNode);
44
+ let [title, description, technology] = astNode.props ?? [];
45
+ const bodyProps = pipe(
46
+ astNode.body?.props ?? [],
47
+ filter(isValid),
48
+ filter(ast.isElementStringProperty),
49
+ mapToObj((p) => [p.key, p.value || void 0])
50
+ );
51
+ title = removeIndent(title ?? bodyProps.title);
52
+ description = removeIndent(bodyProps.description ?? description);
53
+ technology = toSingleLine(bodyProps.technology ?? technology);
54
+ const links = this.parseLinks(astNode.body);
55
+ const iconProp = astNode.body?.props.find(ast.isIconProperty);
56
+ if (iconProp && isValid(iconProp)) {
57
+ const value = iconProp.libicon?.ref?.name ?? iconProp.value;
58
+ if (isTruthy(value)) {
59
+ style.icon = value;
60
+ }
61
+ }
62
+ return {
63
+ id,
64
+ kind,
65
+ astPath,
66
+ title: title ?? astNode.name,
67
+ ...metadata && { metadata },
68
+ ...tags && { tags },
69
+ ...links && isNonEmptyArray(links) && { links },
70
+ ...isTruthy(technology) && { technology },
71
+ ...isTruthy(description) && { description },
72
+ style
73
+ };
74
+ }
75
+ parseRelation(astNode) {
76
+ const isValid = this.isValid;
77
+ const coupling = resolveRelationPoints(astNode);
78
+ const target = this.resolveFqn(coupling.target);
79
+ const source = this.resolveFqn(coupling.source);
80
+ const tags = this.parseTags(astNode) ?? this.parseTags(astNode.body);
81
+ const links = this.parseLinks(astNode.body);
82
+ const kind = astNode.kind?.ref?.name;
83
+ const metadata = this.getMetadata(astNode.body?.props.find(ast.isMetadataProperty));
84
+ const astPath = this.getAstNodePath(astNode);
85
+ const bodyProps = mapToObj(
86
+ astNode.body?.props.filter(ast.isRelationStringProperty).filter((p) => isNonNullish(p.value)) ?? [],
87
+ (p) => [p.key, p.value]
88
+ );
89
+ const navigateTo = pipe(
90
+ astNode.body?.props ?? [],
91
+ filter(ast.isRelationNavigateToProperty),
92
+ map((p) => p.value.view.ref?.name),
93
+ filter(isTruthy),
94
+ first()
95
+ );
96
+ const title = removeIndent(astNode.title ?? bodyProps.title) ?? "";
97
+ const description = removeIndent(bodyProps.description);
98
+ const technology = toSingleLine(astNode.technology) ?? removeIndent(bodyProps.technology);
99
+ const styleProp = astNode.body?.props.find(ast.isRelationStyleProperty);
100
+ const id = stringHash(
101
+ astPath,
102
+ source,
103
+ target
104
+ );
105
+ return {
106
+ id,
107
+ astPath,
108
+ source,
109
+ target,
110
+ title,
111
+ ...metadata && { metadata },
112
+ ...isTruthy(technology) && { technology },
113
+ ...isTruthy(description) && { description },
114
+ ...kind && { kind },
115
+ ...tags && { tags },
116
+ ...isNonEmptyArray(links) && { links },
117
+ ...toRelationshipStyleExcludeDefaults(styleProp?.props, isValid),
118
+ ...navigateTo && { navigateTo }
119
+ };
120
+ }
121
+ };
122
+ }
@@ -0,0 +1,34 @@
1
+ import type * as c4 from '@likec4/core';
2
+ import { ast } from '../../ast';
3
+ import { type Base } from './Base';
4
+ export type WithPredicates = ReturnType<typeof PredicatesParser>;
5
+ export declare function PredicatesParser<TBase extends Base>(B: TBase): {
6
+ new (...args: any[]): {
7
+ parsePredicate(astNode: ast.Predicate): c4.Expression;
8
+ parseElementPredicate(astNode: ast.ElementPredicate): c4.ElementPredicateExpression;
9
+ parseElementExpressionsIterator(astNode: ast.ElementExpressionsIterator): c4.ElementExpression[];
10
+ parseElementExpression(astNode: ast.ElementExpression): c4.ElementExpression;
11
+ parseElementPredicateWhere(astNode: ast.ElementPredicateWhere): c4.ElementWhereExpr;
12
+ parseElementPredicateWith(astNode: ast.ElementPredicateWith): c4.CustomElementExpr;
13
+ parseRelationPredicate(astNode: ast.RelationPredicate): c4.RelationPredicateExpression;
14
+ parseRelationPredicateWhere(astNode: ast.RelationPredicateWhere): c4.RelationWhereExpr;
15
+ parseRelationPredicateWith(astNode: ast.RelationPredicateWith, relation: c4.RelationExpression | c4.RelationWhereExpr): c4.CustomRelationExpr;
16
+ parseRelationExpression(astNode: ast.RelationExpression): c4.RelationExpression;
17
+ isValid: import("../../validation").IsValidFn;
18
+ readonly services: import("../..").LikeC4Services;
19
+ readonly doc: import("../../ast").ParsedLikeC4LangiumDocument;
20
+ resolveFqn(node: ast.FqnReferenceable): c4.Fqn;
21
+ getAstNodePath(node: c4): any;
22
+ getMetadata(metadataAstNode: ast.MetadataProperty | undefined): {
23
+ [key: string]: string;
24
+ } | undefined;
25
+ convertTags<E extends {
26
+ tags?: ast.Tags;
27
+ }>(withTags?: E | undefined): any;
28
+ parseTags<E extends {
29
+ tags?: ast.Tags;
30
+ }>(withTags?: E): c4.NonEmptyArray<c4.Tag> | null;
31
+ convertLinks(source?: ast.LinkProperty["$container"]): import("../../ast").ParsedLink[] | undefined;
32
+ parseLinks(source?: ast.LinkProperty["$container"]): import("../../ast").ParsedLink[] | undefined;
33
+ };
34
+ } & TBase;
@@ -0,0 +1,272 @@
1
+ import { invariant, nonexhaustive } from "@likec4/core";
2
+ import { isDefined, isTruthy } from "remeda";
3
+ import { ast, parseAstOpacityProperty, toColor } from "../../ast.js";
4
+ import { logWarnError } from "../../logger.js";
5
+ import { elementRef } from "../../utils/elementRef.js";
6
+ import { parseWhereClause } from "../model-parser-where.js";
7
+ import { removeIndent } from "./Base.js";
8
+ export function PredicatesParser(B) {
9
+ return class PredicatesParser extends B {
10
+ parsePredicate(astNode) {
11
+ if (ast.isElementPredicate(astNode)) {
12
+ return this.parseElementPredicate(astNode);
13
+ }
14
+ if (ast.isRelationPredicate(astNode)) {
15
+ return this.parseRelationPredicate(astNode);
16
+ }
17
+ nonexhaustive(astNode);
18
+ }
19
+ parseElementPredicate(astNode) {
20
+ if (ast.isElementPredicateWith(astNode)) {
21
+ return this.parseElementPredicateWith(astNode);
22
+ }
23
+ if (ast.isElementPredicateWhere(astNode)) {
24
+ return this.parseElementPredicateWhere(astNode);
25
+ }
26
+ if (ast.isElementExpression(astNode)) {
27
+ return this.parseElementExpression(astNode);
28
+ }
29
+ nonexhaustive(astNode);
30
+ }
31
+ parseElementExpressionsIterator(astNode) {
32
+ const exprs = [];
33
+ let iter = astNode;
34
+ while (iter) {
35
+ try {
36
+ if (iter.value) {
37
+ exprs.unshift(this.parseElementExpression(iter.value));
38
+ }
39
+ } catch (e) {
40
+ logWarnError(e);
41
+ }
42
+ iter = iter.prev;
43
+ }
44
+ return exprs;
45
+ }
46
+ parseElementExpression(astNode) {
47
+ if (ast.isWildcardExpression(astNode)) {
48
+ return {
49
+ wildcard: true
50
+ };
51
+ }
52
+ if (ast.isElementKindExpression(astNode)) {
53
+ invariant(astNode.kind?.ref, "ElementKindExpr kind is not resolved: " + astNode.$cstNode?.text);
54
+ return {
55
+ elementKind: astNode.kind.ref.name,
56
+ isEqual: astNode.isEqual
57
+ };
58
+ }
59
+ if (ast.isElementTagExpression(astNode)) {
60
+ invariant(astNode.tag?.ref, "ElementTagExpr tag is not resolved: " + astNode.$cstNode?.text);
61
+ let elementTag = astNode.tag.$refText;
62
+ if (elementTag.startsWith("#")) {
63
+ elementTag = elementTag.slice(1);
64
+ }
65
+ return {
66
+ elementTag,
67
+ isEqual: astNode.isEqual
68
+ };
69
+ }
70
+ if (ast.isExpandElementExpression(astNode)) {
71
+ const elementNode = elementRef(astNode.expand);
72
+ invariant(elementNode, "Element not found " + astNode.expand.$cstNode?.text);
73
+ const expanded = this.resolveFqn(elementNode);
74
+ return {
75
+ expanded
76
+ };
77
+ }
78
+ if (ast.isElementDescedantsExpression(astNode)) {
79
+ const elementNode = elementRef(astNode.parent);
80
+ invariant(elementNode, "Element not found " + astNode.parent.$cstNode?.text);
81
+ const element = this.resolveFqn(elementNode);
82
+ return {
83
+ element,
84
+ isChildren: astNode.suffix === ".*",
85
+ isDescendants: astNode.suffix === ".**"
86
+ };
87
+ }
88
+ if (ast.isElementRef(astNode)) {
89
+ const elementNode = elementRef(astNode);
90
+ invariant(elementNode, "Element not found " + astNode.$cstNode?.text);
91
+ const element = this.resolveFqn(elementNode);
92
+ return {
93
+ element
94
+ };
95
+ }
96
+ nonexhaustive(astNode);
97
+ }
98
+ parseElementPredicateWhere(astNode) {
99
+ const expr = this.parseElementExpression(astNode.subject);
100
+ return {
101
+ where: {
102
+ expr,
103
+ condition: astNode.where ? parseWhereClause(astNode.where) : {
104
+ kind: { neq: "--always-true--" }
105
+ }
106
+ }
107
+ };
108
+ }
109
+ parseElementPredicateWith(astNode) {
110
+ const expr = this.parseElementPredicate(astNode.subject);
111
+ const props = astNode.custom?.props ?? [];
112
+ return props.reduce(
113
+ (acc, prop) => {
114
+ if (!this.isValid(prop)) {
115
+ return acc;
116
+ }
117
+ if (ast.isNavigateToProperty(prop)) {
118
+ const viewId = prop.value.view.$refText;
119
+ if (isTruthy(viewId)) {
120
+ acc.custom.navigateTo = viewId;
121
+ }
122
+ return acc;
123
+ }
124
+ if (ast.isElementStringProperty(prop)) {
125
+ if (isDefined(prop.value)) {
126
+ acc.custom[prop.key] = removeIndent(prop.value) || "";
127
+ }
128
+ return acc;
129
+ }
130
+ if (ast.isIconProperty(prop)) {
131
+ const value = prop.libicon?.ref?.name ?? prop.value;
132
+ if (isDefined(value)) {
133
+ acc.custom[prop.key] = value;
134
+ }
135
+ return acc;
136
+ }
137
+ if (ast.isColorProperty(prop)) {
138
+ const value = toColor(prop);
139
+ if (isDefined(value)) {
140
+ acc.custom[prop.key] = value;
141
+ }
142
+ return acc;
143
+ }
144
+ if (ast.isShapeProperty(prop)) {
145
+ if (isDefined(prop.value)) {
146
+ acc.custom[prop.key] = prop.value;
147
+ }
148
+ return acc;
149
+ }
150
+ if (ast.isBorderProperty(prop)) {
151
+ if (isDefined(prop.value)) {
152
+ acc.custom[prop.key] = prop.value;
153
+ }
154
+ return acc;
155
+ }
156
+ if (ast.isOpacityProperty(prop)) {
157
+ if (isDefined(prop.value)) {
158
+ acc.custom[prop.key] = parseAstOpacityProperty(prop);
159
+ }
160
+ return acc;
161
+ }
162
+ if (ast.isNotationProperty(prop)) {
163
+ if (isTruthy(prop.value)) {
164
+ acc.custom[prop.key] = removeIndent(prop.value);
165
+ }
166
+ return acc;
167
+ }
168
+ nonexhaustive(prop);
169
+ },
170
+ {
171
+ custom: {
172
+ expr
173
+ }
174
+ }
175
+ );
176
+ }
177
+ parseRelationPredicate(astNode) {
178
+ if (ast.isRelationPredicateWith(astNode)) {
179
+ let relation = ast.isRelationPredicateWhere(astNode.subject) ? this.parseRelationPredicateWhere(astNode.subject) : this.parseRelationExpression(astNode.subject);
180
+ return this.parseRelationPredicateWith(astNode, relation);
181
+ }
182
+ if (ast.isRelationPredicateWhere(astNode)) {
183
+ return this.parseRelationPredicateWhere(astNode);
184
+ }
185
+ if (ast.isRelationExpression(astNode)) {
186
+ return this.parseRelationExpression(astNode);
187
+ }
188
+ nonexhaustive(astNode);
189
+ }
190
+ parseRelationPredicateWhere(astNode) {
191
+ const expr = this.parseRelationExpression(astNode.subject);
192
+ return {
193
+ where: {
194
+ expr,
195
+ condition: astNode.where ? parseWhereClause(astNode.where) : {
196
+ kind: { neq: "--always-true--" }
197
+ }
198
+ }
199
+ };
200
+ }
201
+ parseRelationPredicateWith(astNode, relation) {
202
+ const props = astNode.custom?.props ?? [];
203
+ return props.reduce(
204
+ (acc, prop) => {
205
+ if (ast.isRelationStringProperty(prop) || ast.isNotationProperty(prop) || ast.isNotesProperty(prop)) {
206
+ if (isDefined(prop.value)) {
207
+ acc.customRelation[prop.key] = removeIndent(prop.value) ?? "";
208
+ }
209
+ return acc;
210
+ }
211
+ if (ast.isArrowProperty(prop)) {
212
+ if (isTruthy(prop.value)) {
213
+ acc.customRelation[prop.key] = prop.value;
214
+ }
215
+ return acc;
216
+ }
217
+ if (ast.isColorProperty(prop)) {
218
+ const value = toColor(prop);
219
+ if (isTruthy(value)) {
220
+ acc.customRelation[prop.key] = value;
221
+ }
222
+ return acc;
223
+ }
224
+ if (ast.isLineProperty(prop)) {
225
+ if (isTruthy(prop.value)) {
226
+ acc.customRelation[prop.key] = prop.value;
227
+ }
228
+ return acc;
229
+ }
230
+ if (ast.isRelationNavigateToProperty(prop)) {
231
+ const viewId = prop.value.view.ref?.name;
232
+ if (isTruthy(viewId)) {
233
+ acc.customRelation.navigateTo = viewId;
234
+ }
235
+ return acc;
236
+ }
237
+ nonexhaustive(prop);
238
+ },
239
+ {
240
+ customRelation: {
241
+ relation
242
+ }
243
+ }
244
+ );
245
+ }
246
+ parseRelationExpression(astNode) {
247
+ if (ast.isDirectedRelationExpression(astNode)) {
248
+ return {
249
+ source: this.parseElementExpression(astNode.source.from),
250
+ target: this.parseElementExpression(astNode.target),
251
+ isBidirectional: astNode.source.isBidirectional
252
+ };
253
+ }
254
+ if (ast.isInOutRelationExpression(astNode)) {
255
+ return {
256
+ inout: this.parseElementExpression(astNode.inout.to)
257
+ };
258
+ }
259
+ if (ast.isOutgoingRelationExpression(astNode)) {
260
+ return {
261
+ outgoing: this.parseElementExpression(astNode.from)
262
+ };
263
+ }
264
+ if (ast.isIncomingRelationExpression(astNode)) {
265
+ return {
266
+ incoming: this.parseElementExpression(astNode.to)
267
+ };
268
+ }
269
+ nonexhaustive(astNode);
270
+ }
271
+ };
272
+ }
@@ -0,0 +1,27 @@
1
+ import type * as c4 from '@likec4/core';
2
+ import { ast } from '../../ast';
3
+ import { type Base } from './Base';
4
+ export declare function SpecificationParser<TBase extends Base>(B: TBase): {
5
+ new (...args: any[]): {
6
+ parseSpecification(): void;
7
+ parseSpecificationDeploymentNodeKind({ kind, props }: ast.SpecificationDeploymentNodeKind): {
8
+ [key: c4.DeploymentNodeKind]: c4.DeploymentNodeKindSpecification;
9
+ };
10
+ isValid: import("../../validation").IsValidFn;
11
+ readonly services: import("../..").LikeC4Services;
12
+ readonly doc: import("../../ast").ParsedLikeC4LangiumDocument;
13
+ resolveFqn(node: ast.FqnReferenceable): c4.Fqn;
14
+ getAstNodePath(node: c4): any;
15
+ getMetadata(metadataAstNode: ast.MetadataProperty | undefined): {
16
+ [key: string]: string;
17
+ } | undefined;
18
+ convertTags<E extends {
19
+ tags?: ast.Tags;
20
+ }>(withTags?: E | undefined): any;
21
+ parseTags<E extends {
22
+ tags?: ast.Tags;
23
+ }>(withTags?: E): c4.NonEmptyArray<c4.Tag> | null;
24
+ convertLinks(source?: ast.LinkProperty["$container"]): import("../../ast").ParsedLink[] | undefined;
25
+ parseLinks(source?: ast.LinkProperty["$container"]): import("../../ast").ParsedLink[] | undefined;
26
+ };
27
+ } & TBase;
@@ -0,0 +1,120 @@
1
+ import { filter, isNonNullish, isTruthy, mapToObj, pipe } from "remeda";
2
+ import { ast, toElementStyle, toRelationshipStyleExcludeDefaults } from "../../ast.js";
3
+ import { logger, logWarnError } from "../../logger.js";
4
+ import { removeIndent } from "./Base.js";
5
+ export function SpecificationParser(B) {
6
+ return class SpecificationParser extends B {
7
+ parseSpecification() {
8
+ const {
9
+ parseResult: {
10
+ value: {
11
+ specifications
12
+ }
13
+ },
14
+ c4Specification
15
+ } = this.doc;
16
+ const isValid = this.isValid;
17
+ const element_specs = specifications.flatMap((s) => s.elements.filter(this.isValid));
18
+ for (const { kind, props } of element_specs) {
19
+ try {
20
+ const kindName = kind.name;
21
+ if (!isTruthy(kindName)) {
22
+ continue;
23
+ }
24
+ if (kindName in c4Specification.elements) {
25
+ logger.warn(`Element kind "${kindName}" is already defined`);
26
+ continue;
27
+ }
28
+ const style = props.find(ast.isElementStyleProperty);
29
+ const bodyProps = pipe(
30
+ props.filter(ast.isSpecificationElementStringProperty) ?? [],
31
+ filter((p) => this.isValid(p) && isNonNullish(p.value)),
32
+ mapToObj((p) => [p.key, removeIndent(p.value)])
33
+ );
34
+ c4Specification.elements[kindName] = {
35
+ ...bodyProps,
36
+ style: {
37
+ ...toElementStyle(style?.props, this.isValid)
38
+ }
39
+ };
40
+ } catch (e) {
41
+ logWarnError(e);
42
+ }
43
+ }
44
+ const relations_specs = specifications.flatMap((s) => s.relationships.filter(this.isValid));
45
+ for (const { kind, props } of relations_specs) {
46
+ try {
47
+ const kindName = kind.name;
48
+ if (!isTruthy(kindName)) {
49
+ continue;
50
+ }
51
+ if (kindName in c4Specification.relationships) {
52
+ logger.warn(`Relationship kind "${kindName}" is already defined`);
53
+ continue;
54
+ }
55
+ const bodyProps = pipe(
56
+ props.filter(ast.isSpecificationRelationshipStringProperty) ?? [],
57
+ filter((p) => this.isValid(p) && isNonNullish(p.value)),
58
+ mapToObj((p) => [p.key, removeIndent(p.value)])
59
+ );
60
+ c4Specification.relationships[kindName] = {
61
+ ...bodyProps,
62
+ ...toRelationshipStyleExcludeDefaults(props, this.isValid)
63
+ };
64
+ } catch (e) {
65
+ logWarnError(e);
66
+ }
67
+ }
68
+ const tags_specs = specifications.flatMap((s) => s.tags.filter(this.isValid));
69
+ for (const tagSpec of tags_specs) {
70
+ const tag = tagSpec.tag.name;
71
+ if (isTruthy(tag)) {
72
+ c4Specification.tags.add(tag);
73
+ }
74
+ }
75
+ const deploymentNodes_specs = specifications.flatMap((s) => s.deploymentNodes.filter(isValid));
76
+ for (const deploymentNode of deploymentNodes_specs) {
77
+ try {
78
+ Object.assign(c4Specification.deployments, this.parseSpecificationDeploymentNodeKind(deploymentNode));
79
+ } catch (e) {
80
+ logWarnError(e);
81
+ }
82
+ }
83
+ const colors_specs = specifications.flatMap((s) => s.colors.filter(isValid));
84
+ for (const { name, color } of colors_specs) {
85
+ try {
86
+ const colorName = name.name;
87
+ if (colorName in c4Specification.colors) {
88
+ logger.warn(`Custom color "${colorName}" is already defined`);
89
+ continue;
90
+ }
91
+ c4Specification.colors[colorName] = {
92
+ color
93
+ };
94
+ } catch (e) {
95
+ logWarnError(e);
96
+ }
97
+ }
98
+ }
99
+ parseSpecificationDeploymentNodeKind({ kind, props }) {
100
+ const kindName = kind.name;
101
+ if (!isTruthy(kindName)) {
102
+ throw new Error("DeploymentNodeKind name is not resolved");
103
+ }
104
+ const style = props.find(ast.isElementStyleProperty);
105
+ const bodyProps = pipe(
106
+ props.filter(ast.isSpecificationElementStringProperty) ?? [],
107
+ filter((p) => this.isValid(p) && isNonNullish(p.value)),
108
+ mapToObj((p) => [p.key, removeIndent(p.value)])
109
+ );
110
+ return {
111
+ [kindName]: {
112
+ ...bodyProps,
113
+ style: {
114
+ ...toElementStyle(style?.props, this.isValid)
115
+ }
116
+ }
117
+ };
118
+ }
119
+ };
120
+ }