@likec4/language-server 1.32.2 → 1.34.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 (77) hide show
  1. package/README.md +27 -1
  2. package/dist/Rpc.d.ts +2 -0
  3. package/dist/Rpc.js +24 -6
  4. package/dist/ast.d.ts +6 -5
  5. package/dist/ast.js +3 -0
  6. package/dist/bundled.mjs +3194 -2547
  7. package/dist/formatting/LikeC4Formatter.d.ts +1 -0
  8. package/dist/formatting/LikeC4Formatter.js +25 -1
  9. package/dist/generated/ast.d.ts +21 -12
  10. package/dist/generated/ast.js +21 -9
  11. package/dist/generated/grammar.js +1 -1
  12. package/dist/index.d.ts +0 -1
  13. package/dist/index.js +1 -2
  14. package/dist/lsp/SemanticTokenProvider.js +1 -1
  15. package/dist/mcp/{LikeC4MCPServerFactory.d.ts → NoopLikeC4MCPServer.d.ts} +1 -9
  16. package/dist/mcp/interfaces.d.ts +11 -0
  17. package/dist/mcp/interfaces.js +0 -0
  18. package/dist/mcp/sseserver/MCPServer.d.ts +1 -1
  19. package/dist/mcp/sseserver/MCPServer.js +5 -5
  20. package/dist/mcp/sseserver/MCPServerFactory.js +30 -58
  21. package/dist/mcp/sseserver/{with-mcp-server.d.ts → WithMCPServer.d.ts} +1 -1
  22. package/dist/mcp/tools/_common.d.ts +68 -0
  23. package/dist/mcp/tools/_common.js +14 -0
  24. package/dist/mcp/tools/list-projects.d.ts +6 -0
  25. package/dist/mcp/tools/list-projects.js +31 -0
  26. package/dist/mcp/tools/open-view.d.ts +10 -0
  27. package/dist/mcp/tools/open-view.js +29 -0
  28. package/dist/mcp/tools/read-element.d.ts +10 -0
  29. package/dist/mcp/tools/read-element.js +135 -0
  30. package/dist/mcp/tools/read-project-elements.d.ts +8 -0
  31. package/dist/mcp/tools/read-project-elements.js +93 -0
  32. package/dist/mcp/tools/read-project-summary.d.ts +8 -0
  33. package/dist/mcp/tools/read-project-summary.js +68 -0
  34. package/dist/mcp/tools/read-view.d.ts +10 -0
  35. package/dist/mcp/tools/read-view.js +164 -0
  36. package/dist/mcp/tools/search-element.d.ts +8 -0
  37. package/dist/mcp/tools/search-element.js +105 -0
  38. package/dist/mcp/utils.d.ts +17 -34
  39. package/dist/mcp/utils.js +41 -101
  40. package/dist/model/builder/MergedSpecification.js +8 -4
  41. package/dist/model/index.d.ts +1 -0
  42. package/dist/model/index.js +1 -0
  43. package/dist/model/model-parser-where.d.ts +1 -0
  44. package/dist/model/model-parser-where.js +30 -24
  45. package/dist/model/model-parser.d.ts +140 -0
  46. package/dist/model/parser/Base.d.ts +30 -2
  47. package/dist/model/parser/Base.js +54 -3
  48. package/dist/model/parser/DeploymentModelParser.d.ts +17 -1
  49. package/dist/model/parser/DeploymentModelParser.js +24 -21
  50. package/dist/model/parser/DeploymentViewParser.d.ts +17 -1
  51. package/dist/model/parser/DeploymentViewParser.js +15 -6
  52. package/dist/model/parser/FqnRefParser.d.ts +17 -1
  53. package/dist/model/parser/FqnRefParser.js +42 -16
  54. package/dist/model/parser/GlobalsParser.d.ts +17 -1
  55. package/dist/model/parser/ImportsParser.d.ts +14 -0
  56. package/dist/model/parser/ModelParser.d.ts +17 -1
  57. package/dist/model/parser/ModelParser.js +22 -14
  58. package/dist/model/parser/PredicatesParser.d.ts +17 -1
  59. package/dist/model/parser/SpecificationParser.d.ts +14 -0
  60. package/dist/model/parser/SpecificationParser.js +16 -11
  61. package/dist/model/parser/ValueConverter.d.ts +4 -0
  62. package/dist/model/parser/ValueConverter.js +12 -0
  63. package/dist/model/parser/ViewsParser.d.ts +17 -1
  64. package/dist/model/parser/ViewsParser.js +21 -7
  65. package/dist/module.d.ts +5 -4
  66. package/dist/module.js +6 -7
  67. package/dist/protocol.d.ts +16 -0
  68. package/dist/protocol.js +4 -0
  69. package/dist/validation/property-checks.js +1 -1
  70. package/dist/views/configurable-layouter.js +22 -28
  71. package/dist/views/likec4-views.d.ts +5 -0
  72. package/dist/views/likec4-views.js +6 -1
  73. package/package.json +20 -19
  74. package/dist/mcp/LikeC4MCPTools.d.ts +0 -96
  75. package/dist/mcp/LikeC4MCPTools.js +0 -290
  76. /package/dist/mcp/{LikeC4MCPServerFactory.js → NoopLikeC4MCPServer.js} +0 -0
  77. /package/dist/mcp/sseserver/{with-mcp-server.js → WithMCPServer.js} +0 -0
@@ -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,
@@ -17,7 +17,9 @@ export declare function ExpressionV2Parser<TBase extends Base>(B: TBase): {
17
17
  parseRelationExprWith(astNode: ast.RelationExprWith): c4.RelationExpr.Custom;
18
18
  parseRelationExprOrWhere(astNode: ast.RelationExprOrWhere): c4.RelationExpr.OrWhere;
19
19
  parseRelationExprWhere(astNode: ast.RelationExprWhere): c4.RelationExpr.Where;
20
- parseRelationExpr(astNode: ast.RelationExpr): c4.RelationExpr;
20
+ parseRelationExpr(astNode: ast.RelationExpr): c4.RelationExpr.OrWhere;
21
+ parseInlineKindCondition(astNode: ast.OutgoingRelationExpr): c4.WhereOperator | null;
22
+ wrapInWhere(expr: c4.RelationExpr, condition: c4.WhereOperator | null): c4.RelationExpr.OrWhere;
21
23
  isValid: import("../../validation").IsValidFn;
22
24
  readonly services: import("../..").LikeC4Services;
23
25
  readonly doc: import("../../ast").ParsedLikeC4LangiumDocument;
@@ -31,6 +33,7 @@ export declare function ExpressionV2Parser<TBase extends Base>(B: TBase): {
31
33
  getMetadata(metadataAstNode: ast.MetadataProperty | undefined): {
32
34
  [key: string]: string;
33
35
  } | undefined;
36
+ parseMarkdownOrString(markdownOrString: ast.MarkdownOrString | undefined): c4.MarkdownOrString | undefined;
34
37
  convertTags<E extends {
35
38
  tags?: ast.Tags;
36
39
  }>(withTags?: E | undefined): any;
@@ -43,5 +46,18 @@ export declare function ExpressionV2Parser<TBase extends Base>(B: TBase): {
43
46
  parseColorLiteral(astNode: ast.ColorLiteral): c4.ColorLiteral | undefined;
44
47
  parseElementStyle(elementProps: Array<ast.ElementProperty> | ast.ElementStyleProperty | undefined): import("../../ast").ParsedElementStyle;
45
48
  parseStyleProps(styleProps: Array<ast.StyleProperty> | undefined): import("../../ast").ParsedElementStyle;
49
+ parseTitleDescriptionTechnology(inlineProps: {
50
+ title?: string | undefined;
51
+ description?: string | undefined;
52
+ technology?: string | undefined;
53
+ }, bodyProps: {
54
+ title?: ast.MarkdownOrString | undefined;
55
+ description?: ast.MarkdownOrString | undefined;
56
+ technology?: ast.MarkdownOrString | undefined;
57
+ }): {
58
+ title?: string;
59
+ description?: c4.MarkdownOrString;
60
+ technology?: string;
61
+ };
46
62
  };
47
63
  } & TBase;
@@ -1,10 +1,10 @@
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";
7
- import { parseWhereClause } from "../model-parser-where.js";
7
+ import { createBinaryOperator, parseWhereClause } from "../model-parser-where.js";
8
8
  import { removeIndent } from "./Base.js";
9
9
  export function ExpressionV2Parser(B) {
10
10
  return class ExpressionV2Parser extends B {
@@ -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
  }
@@ -315,31 +317,44 @@ export function ExpressionV2Parser(B) {
315
317
  !ast.isRelationExprWhere(astNode.subject),
316
318
  "RelationExprWhere is not allowed as subject of RelationExprWhere"
317
319
  );
320
+ const relationOrWhereExpr = this.parseRelationExpr(astNode.subject);
321
+ const expr = relationOrWhereExpr.where?.expr ?? relationOrWhereExpr;
322
+ const kindCondition = relationOrWhereExpr.where?.condition;
323
+ const whereCondition = astNode.where ? parseWhereClause(astNode.where) : null;
324
+ let condition;
325
+ if (whereCondition && kindCondition) {
326
+ condition = createBinaryOperator(
327
+ "and",
328
+ kindCondition,
329
+ whereCondition
330
+ );
331
+ } else {
332
+ condition = whereCondition ?? kindCondition ?? { kind: { neq: "--always-true--" } };
333
+ }
318
334
  return {
319
335
  where: {
320
- expr: this.parseRelationExpr(astNode.subject),
321
- condition: astNode.where ? parseWhereClause(astNode.where) : {
322
- kind: { neq: "--always-true--" }
323
- }
336
+ expr,
337
+ condition
324
338
  }
325
339
  };
326
340
  }
327
341
  parseRelationExpr(astNode) {
328
342
  switch (astNode.$type) {
329
343
  case "DirectedRelationExpr":
330
- return {
344
+ return this.wrapInWhere({
331
345
  source: this.parseFqnExpr(astNode.source.from),
332
346
  target: this.parseFqnExpr(astNode.target),
333
347
  isBidirectional: astNode.source.isBidirectional
334
- };
348
+ }, this.parseInlineKindCondition(astNode.source));
335
349
  case "InOutRelationExpr":
336
350
  return {
337
351
  inout: this.parseFqnExpr(astNode.inout.to)
338
352
  };
339
353
  case "OutgoingRelationExpr":
340
- return {
341
- outgoing: this.parseFqnExpr(astNode.from)
342
- };
354
+ return this.wrapInWhere(
355
+ { outgoing: this.parseFqnExpr(astNode.from) },
356
+ this.parseInlineKindCondition(astNode)
357
+ );
343
358
  case "IncomingRelationExpr":
344
359
  return {
345
360
  incoming: this.parseFqnExpr(astNode.to)
@@ -348,5 +363,16 @@ export function ExpressionV2Parser(B) {
348
363
  nonexhaustive(astNode);
349
364
  }
350
365
  }
366
+ parseInlineKindCondition(astNode) {
367
+ const kind = astNode.kind ?? astNode.dotKind?.kind;
368
+ if (kind) {
369
+ invariant(kind.ref, "Kind is not resolved: " + astNode.$cstNode?.text);
370
+ return { kind: { eq: kind.ref?.name } };
371
+ }
372
+ return null;
373
+ }
374
+ wrapInWhere(expr, condition) {
375
+ return condition ? { where: { expr, condition } } : expr;
376
+ }
351
377
  };
352
378
  }
@@ -46,7 +46,9 @@ export declare function GlobalsParser<TBase extends WithViewsParser>(B: TBase):
46
46
  parseRelationExprWith(astNode: ast.RelationExprWith): c4.RelationExpr.Custom;
47
47
  parseRelationExprOrWhere(astNode: ast.RelationExprOrWhere): c4.RelationExpr.OrWhere;
48
48
  parseRelationExprWhere(astNode: ast.RelationExprWhere): c4.RelationExpr.Where;
49
- parseRelationExpr(astNode: ast.RelationExpr): c4.RelationExpr;
49
+ parseRelationExpr(astNode: ast.RelationExpr): c4.RelationExpr.OrWhere;
50
+ parseInlineKindCondition(astNode: ast.OutgoingRelationExpr): c4.WhereOperator | null;
51
+ wrapInWhere(expr: c4.RelationExpr, condition: c4.WhereOperator | null): c4.RelationExpr.OrWhere;
50
52
  isValid: import("../../validation").IsValidFn;
51
53
  readonly services: import("../..").LikeC4Services;
52
54
  readonly doc: import("../../ast").ParsedLikeC4LangiumDocument;
@@ -60,6 +62,7 @@ export declare function GlobalsParser<TBase extends WithViewsParser>(B: TBase):
60
62
  getMetadata(metadataAstNode: ast.MetadataProperty | undefined): {
61
63
  [key: string]: string;
62
64
  } | undefined;
65
+ parseMarkdownOrString(markdownOrString: ast.MarkdownOrString | undefined): c4.MarkdownOrString | undefined;
63
66
  convertTags<E extends {
64
67
  tags?: ast.Tags;
65
68
  }>(withTags?: E | undefined): any;
@@ -72,6 +75,19 @@ export declare function GlobalsParser<TBase extends WithViewsParser>(B: TBase):
72
75
  parseColorLiteral(astNode: ast.ColorLiteral): c4.ColorLiteral | undefined;
73
76
  parseElementStyle(elementProps: Array<ast.ElementProperty> | ast.ElementStyleProperty | undefined): import("../../ast").ParsedElementStyle;
74
77
  parseStyleProps(styleProps: Array<ast.StyleProperty> | undefined): import("../../ast").ParsedElementStyle;
78
+ parseTitleDescriptionTechnology(inlineProps: {
79
+ title?: string | undefined;
80
+ description?: string | undefined;
81
+ technology?: string | undefined;
82
+ }, bodyProps: {
83
+ title?: ast.MarkdownOrString | undefined;
84
+ description?: ast.MarkdownOrString | undefined;
85
+ technology?: ast.MarkdownOrString | undefined;
86
+ }): {
87
+ title?: string;
88
+ description?: c4.MarkdownOrString;
89
+ technology?: string;
90
+ };
75
91
  parseDeploymentView(astNode: ast.DeploymentView): import("../../ast").ParsedAstDeploymentView;
76
92
  parseDeploymentViewRule(astRule: ast.DeploymentViewRule): c4.DeploymentViewRule;
77
93
  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;
@@ -23,7 +23,9 @@ export declare function ModelParser<TBase extends WithExpressionV2>(B: TBase): {
23
23
  parseRelationExprWith(astNode: ast.RelationExprWith): c4.RelationExpr.Custom;
24
24
  parseRelationExprOrWhere(astNode: ast.RelationExprOrWhere): c4.RelationExpr.OrWhere;
25
25
  parseRelationExprWhere(astNode: ast.RelationExprWhere): c4.RelationExpr.Where;
26
- parseRelationExpr(astNode: ast.RelationExpr): c4.RelationExpr;
26
+ parseRelationExpr(astNode: ast.RelationExpr): c4.RelationExpr.OrWhere;
27
+ parseInlineKindCondition(astNode: ast.OutgoingRelationExpr): c4.WhereOperator | null;
28
+ wrapInWhere(expr: c4.RelationExpr, condition: c4.WhereOperator | null): c4.RelationExpr.OrWhere;
27
29
  isValid: import("../../validation").IsValidFn;
28
30
  readonly services: import("../..").LikeC4Services;
29
31
  readonly doc: import("../../ast").ParsedLikeC4LangiumDocument;
@@ -37,6 +39,7 @@ export declare function ModelParser<TBase extends WithExpressionV2>(B: TBase): {
37
39
  getMetadata(metadataAstNode: ast.MetadataProperty | undefined): {
38
40
  [key: string]: string;
39
41
  } | undefined;
42
+ parseMarkdownOrString(markdownOrString: ast.MarkdownOrString | undefined): c4.MarkdownOrString | undefined;
40
43
  convertTags<E extends {
41
44
  tags?: ast.Tags;
42
45
  }>(withTags?: E | undefined): any;
@@ -49,5 +52,18 @@ export declare function ModelParser<TBase extends WithExpressionV2>(B: TBase): {
49
52
  parseColorLiteral(astNode: ast.ColorLiteral): c4.ColorLiteral | undefined;
50
53
  parseElementStyle(elementProps: Array<ast.ElementProperty> | ast.ElementStyleProperty | undefined): import("../../ast").ParsedElementStyle;
51
54
  parseStyleProps(styleProps: Array<ast.StyleProperty> | undefined): import("../../ast").ParsedElementStyle;
55
+ parseTitleDescriptionTechnology(inlineProps: {
56
+ title?: string | undefined;
57
+ description?: string | undefined;
58
+ technology?: string | undefined;
59
+ }, bodyProps: {
60
+ title?: ast.MarkdownOrString | undefined;
61
+ description?: ast.MarkdownOrString | undefined;
62
+ technology?: ast.MarkdownOrString | undefined;
63
+ }): {
64
+ title?: string;
65
+ description?: c4.MarkdownOrString;
66
+ technology?: string;
67
+ };
52
68
  };
53
69
  } & 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 },
@@ -28,7 +28,9 @@ export declare function PredicatesParser<TBase extends WithExpressionV2>(B: TBas
28
28
  parseRelationExprWith(astNode: ast.RelationExprWith): c4.RelationExpr.Custom;
29
29
  parseRelationExprOrWhere(astNode: ast.RelationExprOrWhere): c4.RelationExpr.OrWhere;
30
30
  parseRelationExprWhere(astNode: ast.RelationExprWhere): c4.RelationExpr.Where;
31
- parseRelationExpr(astNode: ast.RelationExpr): c4.RelationExpr;
31
+ parseRelationExpr(astNode: ast.RelationExpr): c4.RelationExpr.OrWhere;
32
+ parseInlineKindCondition(astNode: ast.OutgoingRelationExpr): c4.WhereOperator | null;
33
+ wrapInWhere(expr: c4.RelationExpr, condition: c4.WhereOperator | null): c4.RelationExpr.OrWhere;
32
34
  isValid: import("../../validation").IsValidFn;
33
35
  readonly services: import("../..").LikeC4Services;
34
36
  readonly doc: import("../../ast").ParsedLikeC4LangiumDocument;
@@ -42,6 +44,7 @@ export declare function PredicatesParser<TBase extends WithExpressionV2>(B: TBas
42
44
  getMetadata(metadataAstNode: ast.MetadataProperty | undefined): {
43
45
  [key: string]: string;
44
46
  } | undefined;
47
+ parseMarkdownOrString(markdownOrString: ast.MarkdownOrString | undefined): c4.MarkdownOrString | undefined;
45
48
  convertTags<E extends {
46
49
  tags?: ast.Tags;
47
50
  }>(withTags?: E | undefined): any;
@@ -54,5 +57,18 @@ export declare function PredicatesParser<TBase extends WithExpressionV2>(B: TBas
54
57
  parseColorLiteral(astNode: ast.ColorLiteral): c4.ColorLiteral | undefined;
55
58
  parseElementStyle(elementProps: Array<ast.ElementProperty> | ast.ElementStyleProperty | undefined): import("../../ast").ParsedElementStyle;
56
59
  parseStyleProps(styleProps: Array<ast.StyleProperty> | undefined): import("../../ast").ParsedElementStyle;
60
+ parseTitleDescriptionTechnology(inlineProps: {
61
+ title?: string | undefined;
62
+ description?: string | undefined;
63
+ technology?: string | undefined;
64
+ }, bodyProps: {
65
+ title?: ast.MarkdownOrString | undefined;
66
+ description?: ast.MarkdownOrString | undefined;
67
+ technology?: ast.MarkdownOrString | undefined;
68
+ }): {
69
+ title?: string;
70
+ description?: c4.MarkdownOrString;
71
+ technology?: string;
72
+ };
57
73
  };
58
74
  } & 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
+ }
@@ -44,7 +44,9 @@ export declare function ViewsParser<TBase extends WithPredicates & WithDeploymen
44
44
  parseRelationExprWith(astNode: ast.RelationExprWith): c4.RelationExpr.Custom;
45
45
  parseRelationExprOrWhere(astNode: ast.RelationExprOrWhere): c4.RelationExpr.OrWhere;
46
46
  parseRelationExprWhere(astNode: ast.RelationExprWhere): c4.RelationExpr.Where;
47
- parseRelationExpr(astNode: ast.RelationExpr): c4.RelationExpr;
47
+ parseRelationExpr(astNode: ast.RelationExpr): c4.RelationExpr.OrWhere;
48
+ parseInlineKindCondition(astNode: ast.OutgoingRelationExpr): c4.WhereOperator | null;
49
+ wrapInWhere(expr: c4.RelationExpr, condition: c4.WhereOperator | null): c4.RelationExpr.OrWhere;
48
50
  isValid: import("../../validation").IsValidFn;
49
51
  readonly services: import("../..").LikeC4Services;
50
52
  readonly doc: import("../../ast").ParsedLikeC4LangiumDocument;
@@ -58,6 +60,7 @@ export declare function ViewsParser<TBase extends WithPredicates & WithDeploymen
58
60
  getMetadata(metadataAstNode: ast.MetadataProperty | undefined): {
59
61
  [key: string]: string;
60
62
  } | undefined;
63
+ parseMarkdownOrString(markdownOrString: ast.MarkdownOrString | undefined): c4.MarkdownOrString | undefined;
61
64
  convertTags<E extends {
62
65
  tags?: ast.Tags;
63
66
  }>(withTags?: E | undefined): any;
@@ -70,6 +73,19 @@ export declare function ViewsParser<TBase extends WithPredicates & WithDeploymen
70
73
  parseColorLiteral(astNode: ast.ColorLiteral): c4.ColorLiteral | undefined;
71
74
  parseElementStyle(elementProps: Array<ast.ElementProperty> | ast.ElementStyleProperty | undefined): import("../../ast").ParsedElementStyle;
72
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
+ };
73
89
  parseDeploymentView(astNode: ast.DeploymentView): import("../../ast").ParsedAstDeploymentView;
74
90
  parseDeploymentViewRule(astRule: ast.DeploymentViewRule): c4.DeploymentViewRule;
75
91
  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
@@ -4,9 +4,8 @@ import { type DefaultSharedModuleContext, type LangiumServices, type LangiumShar
4
4
  import { LikeC4DocumentationProvider } from './documentation';
5
5
  import { type LikeC4LanguageServices } from './LikeC4LanguageServices';
6
6
  import { LikeC4CodeLensProvider, LikeC4CompletionProvider, LikeC4DocumentHighlightProvider, LikeC4DocumentLinkProvider, LikeC4DocumentSymbolProvider, LikeC4HoverProvider, LikeC4SemanticTokenProvider } from './lsp';
7
- import { type LikeC4MCPServer, type LikeC4MCPServerFactory } from './mcp/LikeC4MCPServerFactory';
8
- import { type LikeC4MCPTools } from './mcp/LikeC4MCPTools';
9
- import { type LikeC4ModelBuilder, DeploymentsIndex, FqnIndex, LikeC4ModelLocator, LikeC4ModelParser } from './model';
7
+ import { type LikeC4MCPServer, type LikeC4MCPServerFactory } from './mcp/interfaces';
8
+ import { type LikeC4ModelBuilder, DeploymentsIndex, FqnIndex, LikeC4ModelLocator, LikeC4ModelParser, LikeC4ValueConverter } from './model';
10
9
  import { LikeC4ModelChanges } from './model-change/ModelChanges';
11
10
  import { LikeC4NameProvider, LikeC4ScopeComputation, LikeC4ScopeProvider } from './references';
12
11
  import { Rpc } from './Rpc';
@@ -36,7 +35,6 @@ export interface LikeC4AddedServices {
36
35
  ValidatedWorkspaceCache: WorkspaceCache<string, any>;
37
36
  Rpc: Rpc;
38
37
  mcp: {
39
- Tools: LikeC4MCPTools;
40
38
  Server: LikeC4MCPServer;
41
39
  ServerFactory: LikeC4MCPServerFactory;
42
40
  };
@@ -66,6 +64,9 @@ export interface LikeC4AddedServices {
66
64
  ScopeProvider: LikeC4ScopeProvider;
67
65
  };
68
66
  shared?: LikeC4SharedServices;
67
+ parser: {
68
+ ValueConverter: LikeC4ValueConverter;
69
+ };
69
70
  }
70
71
  export type LikeC4Services = LangiumServices & LikeC4AddedServices;
71
72
  export declare const LikeC4Module: Module<LikeC4Services, PartialLangiumServices & LikeC4AddedServices>;