@likec4/language-server 1.32.2 → 1.33.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 (36) hide show
  1. package/dist/ast.d.ts +6 -5
  2. package/dist/ast.js +3 -0
  3. package/dist/bundled.mjs +3342 -2550
  4. package/dist/generated/ast.d.ts +20 -11
  5. package/dist/generated/ast.js +17 -5
  6. package/dist/generated/grammar.js +1 -1
  7. package/dist/lsp/SemanticTokenProvider.js +1 -1
  8. package/dist/mcp/LikeC4MCPTools.js +5 -2
  9. package/dist/model/builder/MergedSpecification.js +8 -4
  10. package/dist/model/index.d.ts +1 -0
  11. package/dist/model/index.js +1 -0
  12. package/dist/model/model-parser.d.ts +126 -0
  13. package/dist/model/parser/Base.d.ts +30 -2
  14. package/dist/model/parser/Base.js +54 -3
  15. package/dist/model/parser/DeploymentModelParser.d.ts +14 -0
  16. package/dist/model/parser/DeploymentModelParser.js +24 -21
  17. package/dist/model/parser/DeploymentViewParser.d.ts +14 -0
  18. package/dist/model/parser/DeploymentViewParser.js +15 -6
  19. package/dist/model/parser/FqnRefParser.d.ts +14 -0
  20. package/dist/model/parser/FqnRefParser.js +8 -6
  21. package/dist/model/parser/GlobalsParser.d.ts +14 -0
  22. package/dist/model/parser/ImportsParser.d.ts +14 -0
  23. package/dist/model/parser/ModelParser.d.ts +14 -0
  24. package/dist/model/parser/ModelParser.js +22 -14
  25. package/dist/model/parser/PredicatesParser.d.ts +14 -0
  26. package/dist/model/parser/SpecificationParser.d.ts +14 -0
  27. package/dist/model/parser/SpecificationParser.js +16 -11
  28. package/dist/model/parser/ValueConverter.d.ts +4 -0
  29. package/dist/model/parser/ValueConverter.js +12 -0
  30. package/dist/model/parser/ViewsParser.d.ts +14 -0
  31. package/dist/model/parser/ViewsParser.js +21 -7
  32. package/dist/module.d.ts +4 -1
  33. package/dist/module.js +5 -1
  34. package/dist/views/configurable-layouter.js +22 -28
  35. package/dist/views/likec4-views.js +0 -1
  36. package/package.json +19 -18
@@ -1,11 +1,11 @@
1
1
  import * as c4 from "@likec4/core";
2
2
  import { invariant, isNonEmptyArray, nonexhaustive } from "@likec4/core";
3
- import { isNonNullish } from "remeda";
4
- import { ast, toAutoLayout, ViewOps } from "../../ast.js";
3
+ import { filter, isNonNullish, mapToObj, pipe } from "remeda";
4
+ import { ast, parseMarkdownAsString, toAutoLayout, ViewOps } from "../../ast.js";
5
5
  import { logWarnError } from "../../logger.js";
6
6
  import { stringHash } from "../../utils/index.js";
7
7
  import { parseViewManualLayout } from "../../view-utils/manual-layout.js";
8
- import { removeIndent, toSingleLine } from "./Base.js";
8
+ import { removeIndent } from "./Base.js";
9
9
  export function DeploymentViewParser(B) {
10
10
  return class DeploymentViewParser extends B {
11
11
  parseDeploymentView(astNode) {
@@ -20,8 +20,17 @@ export function DeploymentViewParser(B) {
20
20
  astPath
21
21
  );
22
22
  }
23
- const title = toSingleLine(props.find((p) => p.key === "title")?.value) ?? null;
24
- const description = removeIndent(props.find((p) => p.key === "description")?.value) ?? null;
23
+ const {
24
+ title = null,
25
+ description = null
26
+ } = this.parseTitleDescriptionTechnology(
27
+ {},
28
+ pipe(
29
+ props,
30
+ filter(ast.isViewStringProperty),
31
+ mapToObj((p) => [p.key, p.value])
32
+ )
33
+ );
25
34
  const tags = this.convertTags(body);
26
35
  const links = this.convertLinks(body);
27
36
  ViewOps.writeId(astNode, id);
@@ -75,7 +84,7 @@ export function DeploymentViewParser(B) {
75
84
  }
76
85
  parseDeploymentViewRuleStyle(astRule) {
77
86
  const style = this.parseStyleProps(astRule.props.filter(ast.isStyleProperty));
78
- const notation = removeIndent(astRule.props.find(ast.isNotationProperty)?.value);
87
+ const notation = removeIndent(parseMarkdownAsString(astRule.props.find(ast.isNotationProperty)?.value));
79
88
  const targets = this.parseFqnExpressions(astRule.targets);
80
89
  return {
81
90
  targets,
@@ -31,6 +31,7 @@ export declare function ExpressionV2Parser<TBase extends Base>(B: TBase): {
31
31
  getMetadata(metadataAstNode: ast.MetadataProperty | undefined): {
32
32
  [key: string]: string;
33
33
  } | undefined;
34
+ parseMarkdownOrString(markdownOrString: ast.MarkdownOrString | undefined): c4.MarkdownOrString | undefined;
34
35
  convertTags<E extends {
35
36
  tags?: ast.Tags;
36
37
  }>(withTags?: E | undefined): any;
@@ -43,5 +44,18 @@ export declare function ExpressionV2Parser<TBase extends Base>(B: TBase): {
43
44
  parseColorLiteral(astNode: ast.ColorLiteral): c4.ColorLiteral | undefined;
44
45
  parseElementStyle(elementProps: Array<ast.ElementProperty> | ast.ElementStyleProperty | undefined): import("../../ast").ParsedElementStyle;
45
46
  parseStyleProps(styleProps: Array<ast.StyleProperty> | undefined): import("../../ast").ParsedElementStyle;
47
+ parseTitleDescriptionTechnology(inlineProps: {
48
+ title?: string | undefined;
49
+ description?: string | undefined;
50
+ technology?: string | undefined;
51
+ }, bodyProps: {
52
+ title?: ast.MarkdownOrString | undefined;
53
+ description?: ast.MarkdownOrString | undefined;
54
+ technology?: ast.MarkdownOrString | undefined;
55
+ }): {
56
+ title?: string;
57
+ description?: c4.MarkdownOrString;
58
+ technology?: string;
59
+ };
46
60
  };
47
61
  } & TBase;
@@ -1,6 +1,6 @@
1
1
  import { invariant, nonexhaustive, nonNullable } from "@likec4/core";
2
2
  import { isBoolean, isDefined, isNonNullish, isTruthy } from "remeda";
3
- import { ast, parseAstOpacityProperty, parseAstSizeValue, toColor } from "../../ast.js";
3
+ import { ast, parseAstOpacityProperty, parseAstSizeValue, parseMarkdownAsString, toColor } from "../../ast.js";
4
4
  import { logWarnError } from "../../logger.js";
5
5
  import { projectIdFrom } from "../../utils/index.js";
6
6
  import { importsRef, instanceRef } from "../../utils/fqnRef.js";
@@ -88,7 +88,7 @@ export function ExpressionV2Parser(B) {
88
88
  }
89
89
  if (ast.isElementStringProperty(prop)) {
90
90
  if (isDefined(prop.value)) {
91
- acc.custom[prop.key] = removeIndent(prop.value) || "";
91
+ acc.custom[prop.key] = removeIndent(parseMarkdownAsString(prop.value)) || "";
92
92
  }
93
93
  return acc;
94
94
  }
@@ -125,8 +125,9 @@ export function ExpressionV2Parser(B) {
125
125
  return acc;
126
126
  }
127
127
  if (ast.isNotationProperty(prop)) {
128
- if (isTruthy(prop.value)) {
129
- acc.custom[prop.key] = removeIndent(prop.value);
128
+ const value = isTruthy(prop.value) ? removeIndent(parseMarkdownAsString(prop.value)) : void 0;
129
+ if (value) {
130
+ acc.custom[prop.key] = value;
130
131
  }
131
132
  return acc;
132
133
  }
@@ -261,8 +262,9 @@ export function ExpressionV2Parser(B) {
261
262
  return props.reduce(
262
263
  (acc, prop) => {
263
264
  if (ast.isRelationStringProperty(prop) || ast.isNotationProperty(prop) || ast.isNotesProperty(prop)) {
264
- if (isDefined(prop.value)) {
265
- acc.customRelation[prop.key] = removeIndent(prop.value) ?? "";
265
+ const value = isTruthy(prop.value) ? removeIndent(parseMarkdownAsString(prop.value)) : void 0;
266
+ if (value) {
267
+ acc.customRelation[prop.key] = value;
266
268
  }
267
269
  return acc;
268
270
  }
@@ -60,6 +60,7 @@ export declare function GlobalsParser<TBase extends WithViewsParser>(B: TBase):
60
60
  getMetadata(metadataAstNode: ast.MetadataProperty | undefined): {
61
61
  [key: string]: string;
62
62
  } | undefined;
63
+ parseMarkdownOrString(markdownOrString: ast.MarkdownOrString | undefined): c4.MarkdownOrString | undefined;
63
64
  convertTags<E extends {
64
65
  tags?: ast.Tags;
65
66
  }>(withTags?: E | undefined): any;
@@ -72,6 +73,19 @@ export declare function GlobalsParser<TBase extends WithViewsParser>(B: TBase):
72
73
  parseColorLiteral(astNode: ast.ColorLiteral): c4.ColorLiteral | undefined;
73
74
  parseElementStyle(elementProps: Array<ast.ElementProperty> | ast.ElementStyleProperty | undefined): import("../../ast").ParsedElementStyle;
74
75
  parseStyleProps(styleProps: Array<ast.StyleProperty> | undefined): import("../../ast").ParsedElementStyle;
76
+ parseTitleDescriptionTechnology(inlineProps: {
77
+ title?: string | undefined;
78
+ description?: string | undefined;
79
+ technology?: string | undefined;
80
+ }, bodyProps: {
81
+ title?: ast.MarkdownOrString | undefined;
82
+ description?: ast.MarkdownOrString | undefined;
83
+ technology?: ast.MarkdownOrString | undefined;
84
+ }): {
85
+ title?: string;
86
+ description?: c4.MarkdownOrString;
87
+ technology?: string;
88
+ };
75
89
  parseDeploymentView(astNode: ast.DeploymentView): import("../../ast").ParsedAstDeploymentView;
76
90
  parseDeploymentViewRule(astRule: ast.DeploymentViewRule): c4.DeploymentViewRule;
77
91
  parseDeploymentViewRulePredicate(astRule: ast.DeploymentViewRulePredicate): c4.DeploymentViewPredicate;
@@ -17,6 +17,7 @@ export declare function ImportsParser<TBase extends Base>(B: TBase): {
17
17
  getMetadata(metadataAstNode: ast.MetadataProperty | undefined): {
18
18
  [key: string]: string;
19
19
  } | undefined;
20
+ parseMarkdownOrString(markdownOrString: ast.MarkdownOrString | undefined): ProjectId | undefined;
20
21
  convertTags<E extends {
21
22
  tags?: ast.Tags;
22
23
  }>(withTags?: E | undefined): any;
@@ -29,5 +30,18 @@ export declare function ImportsParser<TBase extends Base>(B: TBase): {
29
30
  parseColorLiteral(astNode: ast.ColorLiteral): ProjectId | undefined;
30
31
  parseElementStyle(elementProps: Array<ast.ElementProperty> | ast.ElementStyleProperty | undefined): import("../../ast").ParsedElementStyle;
31
32
  parseStyleProps(styleProps: Array<ast.StyleProperty> | undefined): import("../../ast").ParsedElementStyle;
33
+ parseTitleDescriptionTechnology(inlineProps: {
34
+ title?: string | undefined;
35
+ description?: string | undefined;
36
+ technology?: string | undefined;
37
+ }, bodyProps: {
38
+ title?: ast.MarkdownOrString | undefined;
39
+ description?: ast.MarkdownOrString | undefined;
40
+ technology?: ast.MarkdownOrString | undefined;
41
+ }): {
42
+ title?: string;
43
+ description?: ProjectId;
44
+ technology?: string;
45
+ };
32
46
  };
33
47
  } & TBase;
@@ -37,6 +37,7 @@ export declare function ModelParser<TBase extends WithExpressionV2>(B: TBase): {
37
37
  getMetadata(metadataAstNode: ast.MetadataProperty | undefined): {
38
38
  [key: string]: string;
39
39
  } | undefined;
40
+ parseMarkdownOrString(markdownOrString: ast.MarkdownOrString | undefined): c4.MarkdownOrString | undefined;
40
41
  convertTags<E extends {
41
42
  tags?: ast.Tags;
42
43
  }>(withTags?: E | undefined): any;
@@ -49,5 +50,18 @@ export declare function ModelParser<TBase extends WithExpressionV2>(B: TBase): {
49
50
  parseColorLiteral(astNode: ast.ColorLiteral): c4.ColorLiteral | undefined;
50
51
  parseElementStyle(elementProps: Array<ast.ElementProperty> | ast.ElementStyleProperty | undefined): import("../../ast").ParsedElementStyle;
51
52
  parseStyleProps(styleProps: Array<ast.StyleProperty> | undefined): import("../../ast").ParsedElementStyle;
53
+ parseTitleDescriptionTechnology(inlineProps: {
54
+ title?: string | undefined;
55
+ description?: string | undefined;
56
+ technology?: string | undefined;
57
+ }, bodyProps: {
58
+ title?: ast.MarkdownOrString | undefined;
59
+ description?: ast.MarkdownOrString | undefined;
60
+ technology?: ast.MarkdownOrString | undefined;
61
+ }): {
62
+ title?: string;
63
+ description?: c4.MarkdownOrString;
64
+ technology?: string;
65
+ };
52
66
  };
53
67
  } & TBase;
@@ -8,7 +8,6 @@ import {
8
8
  } from "../../ast.js";
9
9
  import { logger as mainLogger } from "../../logger.js";
10
10
  import { stringHash } from "../../utils/stringHash.js";
11
- import { removeIndent, toSingleLine } from "./Base.js";
12
11
  const logger = mainLogger.getChild("ModelParser");
13
12
  function* streamModel(doc) {
14
13
  const traverseStack = LinkedList.from(doc.parseResult.value.models.flatMap((m) => m.elements));
@@ -76,16 +75,21 @@ ${error}`, {
76
75
  const style = this.parseElementStyle(astNode.body?.props);
77
76
  const metadata = this.getMetadata(astNode.body?.props.find(ast.isMetadataProperty));
78
77
  const astPath = this.getAstNodePath(astNode);
79
- let [title, description, technology] = astNode.props ?? [];
78
+ let [_title, _description, _technology] = astNode.props ?? [];
80
79
  const bodyProps = pipe(
81
80
  astNode.body?.props ?? [],
82
81
  filter(isValid),
83
82
  filter(ast.isElementStringProperty),
84
- mapToObj((p) => [p.key, p.value || void 0])
83
+ mapToObj((p) => [p.key, p.value])
84
+ );
85
+ const { title, ...descAndTech } = this.parseTitleDescriptionTechnology(
86
+ {
87
+ title: _title,
88
+ description: _description,
89
+ technology: _technology
90
+ },
91
+ bodyProps
85
92
  );
86
- title = removeIndent(title ?? bodyProps.title);
87
- description = removeIndent(bodyProps.description ?? description);
88
- technology = toSingleLine(bodyProps.technology ?? technology);
89
93
  const links = this.parseLinks(astNode.body);
90
94
  return {
91
95
  id,
@@ -95,8 +99,7 @@ ${error}`, {
95
99
  ...metadata && { metadata },
96
100
  ...tags && { tags },
97
101
  ...links && isNonEmptyArray(links) && { links },
98
- ...isTruthy(technology) && { technology },
99
- ...isTruthy(description) && { description },
102
+ ...descAndTech,
100
103
  style
101
104
  };
102
105
  }
@@ -144,7 +147,7 @@ ${error}`, {
144
147
  astNode.body?.props ?? [],
145
148
  filter(ast.isRelationStringProperty),
146
149
  filter((p) => isTruthy(p.value)),
147
- mapToObj((p) => [p.key, p.value || void 0])
150
+ mapToObj((p) => [p.key, p.value])
148
151
  );
149
152
  const navigateTo = pipe(
150
153
  astNode.body?.props ?? [],
@@ -153,9 +156,15 @@ ${error}`, {
153
156
  filter(isTruthy),
154
157
  first()
155
158
  );
156
- const title = removeIndent(astNode.title ?? bodyProps.title) ?? "";
157
- const description = removeIndent(astNode.description ?? bodyProps.description);
158
- const technology = toSingleLine(astNode.technology) ?? removeIndent(bodyProps.technology);
159
+ const { title = "", ...descAndTech } = this.parseTitleDescriptionTechnology(
160
+ // inline props
161
+ {
162
+ title: astNode.title,
163
+ description: astNode.description,
164
+ technology: astNode.technology
165
+ },
166
+ bodyProps
167
+ );
159
168
  const styleProp = astNode.body?.props.find(ast.isRelationStyleProperty);
160
169
  const id = stringHash(
161
170
  astPath,
@@ -169,8 +178,7 @@ ${error}`, {
169
178
  target,
170
179
  title,
171
180
  ...metadata && { metadata },
172
- ...isTruthy(technology) && { technology },
173
- ...isTruthy(description) && { description },
181
+ ...descAndTech,
174
182
  ...kind && { kind },
175
183
  ...tags && { tags },
176
184
  ...isNonEmptyArray(links) && { links },
@@ -42,6 +42,7 @@ export declare function PredicatesParser<TBase extends WithExpressionV2>(B: TBas
42
42
  getMetadata(metadataAstNode: ast.MetadataProperty | undefined): {
43
43
  [key: string]: string;
44
44
  } | undefined;
45
+ parseMarkdownOrString(markdownOrString: ast.MarkdownOrString | undefined): c4.MarkdownOrString | undefined;
45
46
  convertTags<E extends {
46
47
  tags?: ast.Tags;
47
48
  }>(withTags?: E | undefined): any;
@@ -54,5 +55,18 @@ export declare function PredicatesParser<TBase extends WithExpressionV2>(B: TBas
54
55
  parseColorLiteral(astNode: ast.ColorLiteral): c4.ColorLiteral | undefined;
55
56
  parseElementStyle(elementProps: Array<ast.ElementProperty> | ast.ElementStyleProperty | undefined): import("../../ast").ParsedElementStyle;
56
57
  parseStyleProps(styleProps: Array<ast.StyleProperty> | undefined): import("../../ast").ParsedElementStyle;
58
+ parseTitleDescriptionTechnology(inlineProps: {
59
+ title?: string | undefined;
60
+ description?: string | undefined;
61
+ technology?: string | undefined;
62
+ }, bodyProps: {
63
+ title?: ast.MarkdownOrString | undefined;
64
+ description?: ast.MarkdownOrString | undefined;
65
+ technology?: ast.MarkdownOrString | undefined;
66
+ }): {
67
+ title?: string;
68
+ description?: c4.MarkdownOrString;
69
+ technology?: string;
70
+ };
57
71
  };
58
72
  } & TBase;
@@ -23,6 +23,7 @@ export declare function SpecificationParser<TBase extends Base>(B: TBase): {
23
23
  getMetadata(metadataAstNode: ast.MetadataProperty | undefined): {
24
24
  [key: string]: string;
25
25
  } | undefined;
26
+ parseMarkdownOrString(markdownOrString: ast.MarkdownOrString | undefined): c4.MarkdownOrString | undefined;
26
27
  convertTags<E extends {
27
28
  tags?: ast.Tags;
28
29
  }>(withTags?: E | undefined): any;
@@ -35,5 +36,18 @@ export declare function SpecificationParser<TBase extends Base>(B: TBase): {
35
36
  parseColorLiteral(astNode: ast.ColorLiteral): c4.ColorLiteral | undefined;
36
37
  parseElementStyle(elementProps: Array<ast.ElementProperty> | ast.ElementStyleProperty | undefined): import("../../ast").ParsedElementStyle;
37
38
  parseStyleProps(styleProps: Array<ast.StyleProperty> | undefined): import("../../ast").ParsedElementStyle;
39
+ parseTitleDescriptionTechnology(inlineProps: {
40
+ title?: string | undefined;
41
+ description?: string | undefined;
42
+ technology?: string | undefined;
43
+ }, bodyProps: {
44
+ title?: ast.MarkdownOrString | undefined;
45
+ description?: ast.MarkdownOrString | undefined;
46
+ technology?: ast.MarkdownOrString | undefined;
47
+ }): {
48
+ title?: string;
49
+ description?: c4.MarkdownOrString;
50
+ technology?: string;
51
+ };
38
52
  };
39
53
  } & TBase;
@@ -1,6 +1,6 @@
1
1
  import { nonNullable } from "@likec4/core/utils";
2
- import { filter, isNonNullish, isTruthy, mapToObj, pipe } from "remeda";
3
- import { ast, toRelationshipStyleExcludeDefaults } from "../../ast.js";
2
+ import { filter, isNonNullish, isNullish, isTruthy, mapToObj, omitBy, pipe } from "remeda";
3
+ import { ast, parseMarkdownAsString, toRelationshipStyleExcludeDefaults } from "../../ast.js";
4
4
  import { logger, logWarnError } from "../../logger.js";
5
5
  import { removeIndent } from "./Base.js";
6
6
  export function SpecificationParser(B) {
@@ -43,7 +43,8 @@ export function SpecificationParser(B) {
43
43
  const bodyProps = pipe(
44
44
  props.filter(ast.isSpecificationRelationshipStringProperty) ?? [],
45
45
  filter((p) => this.isValid(p) && isNonNullish(p.value)),
46
- mapToObj((p) => [p.key, removeIndent(p.value)])
46
+ mapToObj((p) => [p.key, removeIndent(parseMarkdownAsString(p.value))]),
47
+ omitBy(isNullish)
47
48
  );
48
49
  c4Specification.relationships[kindName] = {
49
50
  ...bodyProps,
@@ -55,14 +56,18 @@ export function SpecificationParser(B) {
55
56
  }
56
57
  const tags_specs = specifications.flatMap((s) => s.tags.filter(this.isValid));
57
58
  for (const tagSpec of tags_specs) {
58
- const tag = tagSpec.tag.name;
59
- const astPath = this.getAstNodePath(tagSpec.tag);
60
- const color = tagSpec.color && this.parseColorLiteral(tagSpec.color);
61
- if (isTruthy(tag)) {
62
- c4Specification.tags[tag] = {
63
- astPath,
64
- ...color ? { color } : {}
65
- };
59
+ try {
60
+ const tag = tagSpec.tag.name;
61
+ const astPath = this.getAstNodePath(tagSpec.tag);
62
+ const color = tagSpec.color && this.parseColorLiteral(tagSpec.color);
63
+ if (isTruthy(tag)) {
64
+ c4Specification.tags[tag] = {
65
+ astPath,
66
+ ...color ? { color } : {}
67
+ };
68
+ }
69
+ } catch (e) {
70
+ logWarnError(e);
66
71
  }
67
72
  }
68
73
  const colors_specs = specifications.flatMap((s) => s.colors.filter(isValid));
@@ -0,0 +1,4 @@
1
+ import { type CstNode, type ValueType, DefaultValueConverter } from 'langium';
2
+ export declare class LikeC4ValueConverter extends DefaultValueConverter {
3
+ protected runConverter(rule: any, input: string, cstNode: CstNode): ValueType;
4
+ }
@@ -0,0 +1,12 @@
1
+ import { DefaultValueConverter, ValueConverter } from "langium";
2
+ export class LikeC4ValueConverter extends DefaultValueConverter {
3
+ runConverter(rule, input, cstNode) {
4
+ if (rule.name === "MarkdownString") {
5
+ if (input.startsWith('"""') && input.endsWith('"""') || input.startsWith(`'''`) && input.endsWith(`'''`)) {
6
+ input = input.slice(3, -3);
7
+ }
8
+ return ValueConverter.convertString(input);
9
+ }
10
+ return super.runConverter(rule, input, cstNode);
11
+ }
12
+ }
@@ -58,6 +58,7 @@ export declare function ViewsParser<TBase extends WithPredicates & WithDeploymen
58
58
  getMetadata(metadataAstNode: ast.MetadataProperty | undefined): {
59
59
  [key: string]: string;
60
60
  } | undefined;
61
+ parseMarkdownOrString(markdownOrString: ast.MarkdownOrString | undefined): c4.MarkdownOrString | undefined;
61
62
  convertTags<E extends {
62
63
  tags?: ast.Tags;
63
64
  }>(withTags?: E | undefined): any;
@@ -70,6 +71,19 @@ export declare function ViewsParser<TBase extends WithPredicates & WithDeploymen
70
71
  parseColorLiteral(astNode: ast.ColorLiteral): c4.ColorLiteral | undefined;
71
72
  parseElementStyle(elementProps: Array<ast.ElementProperty> | ast.ElementStyleProperty | undefined): import("../../ast").ParsedElementStyle;
72
73
  parseStyleProps(styleProps: Array<ast.StyleProperty> | undefined): import("../../ast").ParsedElementStyle;
74
+ parseTitleDescriptionTechnology(inlineProps: {
75
+ title?: string | undefined;
76
+ description?: string | undefined;
77
+ technology?: string | undefined;
78
+ }, bodyProps: {
79
+ title?: ast.MarkdownOrString | undefined;
80
+ description?: ast.MarkdownOrString | undefined;
81
+ technology?: ast.MarkdownOrString | undefined;
82
+ }): {
83
+ title?: string;
84
+ description?: c4.MarkdownOrString;
85
+ technology?: string;
86
+ };
73
87
  parseDeploymentView(astNode: ast.DeploymentView): import("../../ast").ParsedAstDeploymentView;
74
88
  parseDeploymentViewRule(astRule: ast.DeploymentViewRule): c4.DeploymentViewRule;
75
89
  parseDeploymentViewRulePredicate(astRule: ast.DeploymentViewRulePredicate): c4.DeploymentViewPredicate;
@@ -1,8 +1,9 @@
1
1
  import * as c4 from "@likec4/core";
2
2
  import { invariant, isNonEmptyArray, nonexhaustive } from "@likec4/core";
3
- import { isArray, isDefined, isNonNullish, isTruthy } from "remeda";
3
+ import { filter, isArray, isDefined, isNonNullish, isTruthy, mapToObj, pipe } from "remeda";
4
4
  import {
5
5
  ast,
6
+ parseMarkdownAsString,
6
7
  toAutoLayout,
7
8
  toColor,
8
9
  ViewOps
@@ -71,8 +72,15 @@ export function ViewsParser(B) {
71
72
  viewOf ?? ""
72
73
  );
73
74
  }
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;
75
+ const { title = null, description = null } = this.parseTitleDescriptionTechnology(
76
+ {},
77
+ pipe(
78
+ body.props,
79
+ filter((p) => this.isValid(p)),
80
+ filter(ast.isViewStringProperty),
81
+ mapToObj((p) => [p.key, p.value])
82
+ )
83
+ );
76
84
  const tags = this.convertTags(body);
77
85
  const links = this.convertLinks(body);
78
86
  const manualLayout = parseViewManualLayout(astNode);
@@ -191,7 +199,7 @@ export function ViewsParser(B) {
191
199
  (e) => c4.ModelExpression.isFqnExpr(e)
192
200
  );
193
201
  const style = this.parseStyleProps(astRule.props.filter(ast.isStyleProperty));
194
- const notation = removeIndent(astRule.props.find(ast.isNotationProperty)?.value);
202
+ const notation = removeIndent(parseMarkdownAsString(astRule.props.find(ast.isNotationProperty)?.value));
195
203
  return {
196
204
  targets,
197
205
  style,
@@ -216,8 +224,14 @@ export function ViewsParser(B) {
216
224
  astPath
217
225
  );
218
226
  }
219
- const title = toSingleLine(props.find((p) => p.key === "title")?.value) ?? null;
220
- const description = removeIndent(props.find((p) => p.key === "description")?.value) ?? null;
227
+ const { title = null, description = null } = this.parseTitleDescriptionTechnology(
228
+ {},
229
+ pipe(
230
+ props,
231
+ filter(ast.isViewStringProperty),
232
+ mapToObj((p) => [p.key, p.value])
233
+ )
234
+ );
221
235
  const tags = this.convertTags(body);
222
236
  const links = this.convertLinks(body);
223
237
  ViewOps.writeId(astNode, id);
@@ -338,7 +352,7 @@ export function ViewsParser(B) {
338
352
  case ast.isNotationProperty(prop):
339
353
  case ast.isNotesProperty(prop): {
340
354
  if (isDefined(prop.value)) {
341
- step[prop.key] = removeIndent(prop.value) ?? "";
355
+ step[prop.key] = removeIndent(parseMarkdownAsString(prop.value)) ?? "";
342
356
  }
343
357
  break;
344
358
  }
package/dist/module.d.ts CHANGED
@@ -6,7 +6,7 @@ import { type LikeC4LanguageServices } from './LikeC4LanguageServices';
6
6
  import { LikeC4CodeLensProvider, LikeC4CompletionProvider, LikeC4DocumentHighlightProvider, LikeC4DocumentLinkProvider, LikeC4DocumentSymbolProvider, LikeC4HoverProvider, LikeC4SemanticTokenProvider } from './lsp';
7
7
  import { type LikeC4MCPServer, type LikeC4MCPServerFactory } from './mcp/LikeC4MCPServerFactory';
8
8
  import { type LikeC4MCPTools } from './mcp/LikeC4MCPTools';
9
- import { type LikeC4ModelBuilder, DeploymentsIndex, FqnIndex, LikeC4ModelLocator, LikeC4ModelParser } from './model';
9
+ import { type LikeC4ModelBuilder, DeploymentsIndex, FqnIndex, LikeC4ModelLocator, LikeC4ModelParser, LikeC4ValueConverter } from './model';
10
10
  import { LikeC4ModelChanges } from './model-change/ModelChanges';
11
11
  import { LikeC4NameProvider, LikeC4ScopeComputation, LikeC4ScopeProvider } from './references';
12
12
  import { Rpc } from './Rpc';
@@ -66,6 +66,9 @@ export interface LikeC4AddedServices {
66
66
  ScopeProvider: LikeC4ScopeProvider;
67
67
  };
68
68
  shared?: LikeC4SharedServices;
69
+ parser: {
70
+ ValueConverter: LikeC4ValueConverter;
71
+ };
69
72
  }
70
73
  export type LikeC4Services = LangiumServices & LikeC4AddedServices;
71
74
  export declare const LikeC4Module: Module<LikeC4Services, PartialLangiumServices & LikeC4AddedServices>;
package/dist/module.js CHANGED
@@ -35,7 +35,8 @@ import {
35
35
  DeploymentsIndex,
36
36
  FqnIndex,
37
37
  LikeC4ModelLocator,
38
- LikeC4ModelParser
38
+ LikeC4ModelParser,
39
+ LikeC4ValueConverter
39
40
  } from "./model/index.js";
40
41
  import { LikeC4ModelChanges } from "./model-change/ModelChanges.js";
41
42
  import {
@@ -116,6 +117,9 @@ export const LikeC4Module = {
116
117
  NameProvider: bind(LikeC4NameProvider),
117
118
  ScopeComputation: bind(LikeC4ScopeComputation),
118
119
  ScopeProvider: bind(LikeC4ScopeProvider)
120
+ },
121
+ parser: {
122
+ ValueConverter: bind(LikeC4ValueConverter)
119
123
  }
120
124
  };
121
125
  export function createCustomLanguageServices(context, module, module2, module3) {
@@ -15,41 +15,35 @@ export const ConfigurableLayouter = {
15
15
  likec4: {
16
16
  Layouter(services) {
17
17
  logger.debug("Creating ConfigurableLayouter");
18
- const wasmAdapter = new GraphvizWasmAdapter();
19
- const layouter = new QueueGraphvizLayoter({
20
- graphviz: wasmAdapter
21
- });
22
- const langId = services.LanguageMetaData.languageId;
18
+ const layouter = new QueueGraphvizLayoter();
23
19
  services.shared.workspace.ConfigurationProvider.onConfigurationSectionUpdate((update) => {
24
20
  logger.debug("Configuration update: {update}", { update });
25
- if (update.section === langId) {
26
- try {
27
- const { mode, path } = update.configuration.graphviz ?? {
28
- mode: "wasm",
29
- path: ""
30
- };
31
- if (mode === "wasm") {
32
- layouter.changePort(wasmAdapter);
33
- logger.info("use graphviz wasm");
34
- return;
35
- }
21
+ if (update.section !== services.LanguageMetaData.languageId) {
22
+ logger.debug(`Ignoring configuration update as it is not for ${services.LanguageMetaData.languageId}`);
23
+ return;
24
+ }
25
+ try {
26
+ const { mode, path } = update.configuration.graphviz ?? {
27
+ mode: "wasm",
28
+ path: ""
29
+ };
30
+ if (mode !== "wasm") {
36
31
  let binaryPath = isEmpty(path) ? graphvizBinPath() : path;
37
- if (binaryPath === null) {
38
- layouter.changePort(wasmAdapter);
39
- logger.warn(`No Graphviz binaries found on PATH, use graphviz wasm`);
40
- services.shared.lsp.Connection?.window.showWarningMessage(
41
- "No Graphviz binaries found on PATH, set path to binaries in settings."
42
- );
32
+ if (!isEmpty(binaryPath)) {
33
+ layouter.changePort(new GraphvizBinaryAdapter(binaryPath));
34
+ logger.info`use graphviz binary: ${binaryPath}`;
43
35
  return;
44
36
  }
45
- layouter.changePort(new GraphvizBinaryAdapter(binaryPath));
46
- logger.info`use graphviz binary: ${binaryPath}`;
47
- } catch (error) {
48
- logger.error("Failed to update configuration", { error });
37
+ logger.warn(`No Graphviz binaries found on PATH, use graphviz wasm`);
38
+ services.shared.lsp.Connection?.window.showWarningMessage(
39
+ "No Graphviz binaries found on PATH, set path to binaries in settings."
40
+ );
49
41
  }
50
- return;
42
+ layouter.changePort(new GraphvizWasmAdapter());
43
+ logger.info("use graphviz wasm");
44
+ } catch (error) {
45
+ logger.error("Failed to update configuration", { error });
51
46
  }
52
- logger.warn("Unexpected configuration update: {update}", { update });
53
47
  });
54
48
  return layouter;
55
49
  }
@@ -53,7 +53,6 @@ export class DefaultLikeC4Views {
53
53
  },
54
54
  onError: (task, error) => {
55
55
  logger.warn(`Fail layout view ${task.view.id}`, { error });
56
- this.cache.delete(task.view);
57
56
  }
58
57
  });
59
58
  }