@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
@@ -0,0 +1,68 @@
1
+ import { invariant } from "@likec4/core";
2
+ import { keys } from "remeda";
3
+ import z from "zod";
4
+ import { ProjectsManager } from "../../workspace/index.js";
5
+ import { likec4Tool } from "../utils.js";
6
+ import { locationSchema } from "./_common.js";
7
+ export const readProjectSummary = likec4Tool({
8
+ name: "read-project-summary",
9
+ annotations: {
10
+ readOnlyHint: true
11
+ },
12
+ description: `
13
+ Searches for LikeC4 project by name in workspace and returns its summary:
14
+ - project folder
15
+ - array of the source filenames
16
+ - specification:
17
+ - all element kinds
18
+ - all relationship kinds
19
+ - all deployment kinds
20
+ - all tags (used and unused)
21
+ - used metadata keys
22
+ - array of the views, where each view:
23
+ - name
24
+ - type ("element", "deployment", "dynamic")
25
+ - title
26
+ `,
27
+ inputSchema: {
28
+ project: z.string().optional().describe('Project name (optional, will use "default" if not specified)')
29
+ },
30
+ outputSchema: {
31
+ folder: z.string(),
32
+ sources: z.array(z.string()),
33
+ specification: z.object({
34
+ elementKinds: z.array(z.string()),
35
+ relationshipKinds: z.array(z.string()),
36
+ deploymentKinds: z.array(z.string()),
37
+ tags: z.array(z.string()),
38
+ metadataKeys: z.array(z.string())
39
+ }),
40
+ views: z.array(z.object({
41
+ name: z.string(),
42
+ title: z.string().nullable(),
43
+ type: z.enum(["element", "deployment", "dynamic"]),
44
+ sourceLocation: locationSchema.nullish()
45
+ }))
46
+ }
47
+ }, async (languageServices, args) => {
48
+ const projectId = args.project ?? ProjectsManager.DefaultProjectId;
49
+ const project = languageServices.projects().find((p) => p.id === projectId);
50
+ invariant(project, `Project "${projectId}" not found`);
51
+ const model = await languageServices.computedModel(project.id);
52
+ return {
53
+ folder: project.folder.toString(),
54
+ sources: project.documents?.map((d) => d.toString()) ?? [],
55
+ specification: {
56
+ elementKinds: keys(model.specification.elements),
57
+ relationshipKinds: keys(model.specification.relationships),
58
+ deploymentKinds: keys(model.specification.deployments),
59
+ tags: [...model.tags],
60
+ metadataKeys: model.specification.metadataKeys ?? []
61
+ },
62
+ views: [...model.views()].map((v) => ({
63
+ name: v.id,
64
+ title: v.title,
65
+ type: v.$view._type
66
+ }))
67
+ };
68
+ });
@@ -0,0 +1,10 @@
1
+ import z from 'zod';
2
+ export declare const readView: (languageServices: import("../..").LikeC4LanguageServices) => [string, {
3
+ inputSchema?: {
4
+ viewId: z.ZodString;
5
+ project: z.ZodOptional<z.ZodString>;
6
+ } | undefined;
7
+ }, (args: {
8
+ viewId: string;
9
+ project?: string | undefined;
10
+ }, extra: import("@modelcontextprotocol/sdk/shared/protocol").RequestHandlerExtra<import("@modelcontextprotocol/sdk/types").ServerRequest, import("@modelcontextprotocol/sdk/types").ServerNotification>) => import("@modelcontextprotocol/sdk/types").CallToolResult | Promise<import("@modelcontextprotocol/sdk/types").CallToolResult>];
@@ -0,0 +1,164 @@
1
+ import { invariant } from "@likec4/core";
2
+ import z from "zod";
3
+ import { safeCall } from "../../utils/index.js";
4
+ import { ProjectsManager } from "../../workspace/index.js";
5
+ import { likec4Tool } from "../utils.js";
6
+ import { locationSchema } from "./_common.js";
7
+ const modelRef = (node) => {
8
+ if (node.hasElement()) {
9
+ return node.element.id;
10
+ }
11
+ if (node.hasDeployment()) {
12
+ return node.deployment.id;
13
+ }
14
+ return null;
15
+ };
16
+ export const readView = likec4Tool({
17
+ name: "read-view",
18
+ description: `
19
+ Returns information about LikeC4 view, includes:
20
+ - id (view name)
21
+ - type (element, deployment, dynamic)
22
+ - title, description, tags
23
+ - project name this view belongs to
24
+ - array of elements included in this view
25
+ - array of relationships in this view (source, target, title, description, technology, tags)
26
+ - viewOf (element id this view is the default view of)
27
+ - source location (if running in the editor)
28
+ `.trimStart(),
29
+ annotations: {
30
+ readOnlyHint: true
31
+ },
32
+ inputSchema: {
33
+ viewId: z.string().describe("View id (name)"),
34
+ project: z.string().optional().describe('Project name (optional, will use "default" if not specified)')
35
+ },
36
+ outputSchema: {
37
+ id: z.string(),
38
+ type: z.enum(["element", "deployment", "dynamic"]),
39
+ title: z.string().nullish(),
40
+ description: z.string().nullish(),
41
+ tags: z.array(z.string()),
42
+ project: z.string(),
43
+ elements: z.array(
44
+ z.discriminatedUnion("type", [
45
+ z.object({
46
+ type: z.literal("logical"),
47
+ id: z.string().describe("Element ID (FQN)"),
48
+ kind: z.string().describe("Element kind"),
49
+ title: z.string().describe("Element title"),
50
+ description: z.string().nullish(),
51
+ technology: z.string().nullish(),
52
+ children: z.array(z.string()),
53
+ shape: z.string().describe("Element shape"),
54
+ tags: z.array(z.string())
55
+ }),
56
+ z.object({
57
+ type: z.literal("deployment-node"),
58
+ id: z.string().describe("Deployment ID (FQN)"),
59
+ kind: z.string().describe("Deployment kind"),
60
+ title: z.string().describe("Deployment title"),
61
+ description: z.string().nullish(),
62
+ technology: z.string().nullish(),
63
+ children: z.array(z.string()),
64
+ shape: z.string().describe("Deployment shape"),
65
+ tags: z.array(z.string())
66
+ }),
67
+ z.object({
68
+ type: z.literal("deployed-instance"),
69
+ id: z.string().describe("Deployment ID (FQN)"),
70
+ title: z.string().describe("Deployment title"),
71
+ description: z.string().nullish(),
72
+ technology: z.string().nullish(),
73
+ logicalElementId: z.string().describe("Logical element ID (FQN)"),
74
+ shape: z.string().describe("Deployment shape"),
75
+ tags: z.array(z.string())
76
+ })
77
+ ])
78
+ ).describe("Elements in this view"),
79
+ relationships: z.array(
80
+ z.object({
81
+ source: z.string().describe("Source element ID"),
82
+ target: z.string().describe("Target element ID"),
83
+ title: z.string().nullish(),
84
+ description: z.string().nullish(),
85
+ technology: z.string().nullish(),
86
+ tags: z.array(z.string())
87
+ })
88
+ ).describe("Relationships in this view"),
89
+ defaultViewOf: z.string().optional().describe("Element ID (FQN) this view is the default view of"),
90
+ sourceLocation: locationSchema.nullish()
91
+ }
92
+ }, async (languageServices, args) => {
93
+ const projectId = args.project ?? ProjectsManager.DefaultProjectId;
94
+ const project = languageServices.projects().find((p) => p.id === projectId);
95
+ invariant(project, `Project "${projectId}" not found`);
96
+ const model = await languageServices.computedModel(project.id);
97
+ const view = model.findView(args.viewId);
98
+ if (!view) {
99
+ throw new Error(`View with ID '${args.viewId}' not found in project ${project.id}`);
100
+ }
101
+ return {
102
+ id: view.id,
103
+ type: view.$view._type,
104
+ title: view.title,
105
+ description: view.description.text,
106
+ tags: [...view.tags],
107
+ project: project.id,
108
+ elements: [...view.nodes()].flatMap((node) => {
109
+ if (node.hasDeployedInstance()) {
110
+ return {
111
+ type: "deployed-instance",
112
+ id: node.deployment.id,
113
+ title: node.title,
114
+ logicalElementId: node.deployment.element.id,
115
+ description: node.description.text,
116
+ technology: node.technology,
117
+ shape: node.shape,
118
+ tags: [...node.tags]
119
+ };
120
+ }
121
+ if (node.hasDeployment()) {
122
+ return {
123
+ type: "deployment-node",
124
+ id: node.deployment.id,
125
+ title: node.title,
126
+ kind: node.deployment.kind,
127
+ description: node.description.text,
128
+ technology: node.technology,
129
+ shape: node.shape,
130
+ tags: [...node.tags],
131
+ children: [...node.children()].flatMap((c) => modelRef(c) ?? [])
132
+ };
133
+ }
134
+ if (node.hasElement()) {
135
+ return {
136
+ type: "logical",
137
+ id: node.element.id,
138
+ title: node.title,
139
+ kind: node.element.kind,
140
+ description: node.description.text,
141
+ technology: node.technology,
142
+ shape: node.shape,
143
+ tags: [...node.tags],
144
+ children: [...node.children()].flatMap((c) => modelRef(c) ?? [])
145
+ };
146
+ }
147
+ return [];
148
+ }),
149
+ viewOf: view.viewOf?.id,
150
+ relationships: [...view.edges()].flatMap((r) => {
151
+ const source = modelRef(r.source);
152
+ const target = modelRef(r.target);
153
+ return source && target ? [{
154
+ source,
155
+ target,
156
+ title: r.label,
157
+ description: r.description.text,
158
+ technology: r.technology,
159
+ tags: [...r.tags]
160
+ }] : [];
161
+ }),
162
+ sourceLocation: safeCall(() => languageServices.locate({ view: view.id, projectId }))
163
+ };
164
+ });
@@ -0,0 +1,8 @@
1
+ import z from 'zod';
2
+ export declare const searchElement: (languageServices: import("../..").LikeC4LanguageServices) => [string, {
3
+ inputSchema?: {
4
+ search: z.ZodString;
5
+ } | undefined;
6
+ }, (args: {
7
+ search: string;
8
+ }, extra: import("@modelcontextprotocol/sdk/shared/protocol").RequestHandlerExtra<import("@modelcontextprotocol/sdk/types").ServerRequest, import("@modelcontextprotocol/sdk/types").ServerNotification>) => import("@modelcontextprotocol/sdk/types").CallToolResult | Promise<import("@modelcontextprotocol/sdk/types").CallToolResult>];
@@ -0,0 +1,105 @@
1
+ import { ifilter } from "@likec4/core/utils";
2
+ import z from "zod";
3
+ import { likec4Tool } from "../utils.js";
4
+ const searchResultSchema = z.array(
5
+ z.discriminatedUnion("type", [
6
+ z.object({
7
+ type: z.literal("logical"),
8
+ id: z.string().describe("Element ID (FQN)"),
9
+ kind: z.string(),
10
+ title: z.string(),
11
+ shape: z.string(),
12
+ project: z.string().describe("Project name"),
13
+ tags: z.array(z.string())
14
+ }),
15
+ z.object({
16
+ type: z.literal("deployment-node"),
17
+ id: z.string().describe("Deployment ID (FQN)"),
18
+ kind: z.string(),
19
+ title: z.string(),
20
+ shape: z.string(),
21
+ project: z.string().describe("Project name"),
22
+ tags: z.array(z.string())
23
+ })
24
+ ])
25
+ );
26
+ export const searchElement = likec4Tool({
27
+ name: "search-element",
28
+ annotations: {
29
+ readOnlyHint: true
30
+ },
31
+ description: `
32
+ Search for LikeC4 elements and deployment nodes by partial match of:
33
+ - id (FQN)
34
+ - title
35
+ - kind (if search string starts with "kind:")
36
+ - shape (if search string starts with "shape:")
37
+ - any assigned tags (if search string starts with "#")
38
+
39
+ Returns array of found elements with:
40
+ - type (logical or deployment-node)
41
+ - id (FQN)
42
+ - kind
43
+ - title
44
+ - shape
45
+ - project name this element belongs to
46
+ - assigned tags
47
+
48
+ Can be used for further requests (like read-element or read-project-summary)
49
+ `.trimStart(),
50
+ inputSchema: {
51
+ search: z.string().min(2, "Search must be at least 2 characters long")
52
+ },
53
+ outputSchema: {
54
+ found: searchResultSchema
55
+ }
56
+ }, async (languageServices, args) => {
57
+ const projects = languageServices.projects();
58
+ const found = [];
59
+ let search = args.search.toLowerCase();
60
+ let predicate;
61
+ if (search.startsWith("kind:")) {
62
+ search = search.slice(5);
63
+ predicate = (el) => el.kind.toLowerCase().includes(search);
64
+ } else if (search.startsWith("shape:")) {
65
+ search = search.slice(6);
66
+ predicate = (el) => el.shape.toLowerCase().includes(search);
67
+ } else if (search.startsWith("#")) {
68
+ search = search.slice(1);
69
+ predicate = (el) => el.tags.some((tag) => tag.toLowerCase().includes(search));
70
+ } else {
71
+ predicate = (el) => el.id.toLowerCase().includes(search) || el.title.toLowerCase().includes(search);
72
+ }
73
+ for (const project of projects) {
74
+ try {
75
+ const model = await languageServices.computedModel(project.id);
76
+ for (const el of ifilter(model.elements(), predicate)) {
77
+ found.push({
78
+ type: "logical",
79
+ id: el.id,
80
+ kind: el.kind,
81
+ title: el.title,
82
+ shape: el.shape,
83
+ project: project.id,
84
+ tags: [...el.tags]
85
+ });
86
+ }
87
+ for (const el of ifilter(model.deployment.nodes(), predicate)) {
88
+ found.push({
89
+ type: "deployment-node",
90
+ id: el.id,
91
+ kind: el.kind,
92
+ title: el.title,
93
+ shape: el.shape,
94
+ project: project.id,
95
+ tags: [...el.tags]
96
+ });
97
+ }
98
+ } catch (error) {
99
+ console.error(`Error searching in project ${project.id}:`, error);
100
+ }
101
+ }
102
+ return {
103
+ found
104
+ };
105
+ });
@@ -1,35 +1,18 @@
1
- import { type Any, type aux, type ProjectId } from '@likec4/core';
2
- import { type ElementModel, type LikeC4ViewModel } from '@likec4/core/model';
1
+ import type { RequestHandlerExtra } from '@modelcontextprotocol/sdk/shared/protocol.js';
2
+ import type { ServerNotification, ServerRequest, ToolAnnotations } from '@modelcontextprotocol/sdk/types.js';
3
+ import type { z, ZodRawShape, ZodTypeAny } from 'zod';
4
+ import type { ToolCallback } from '@modelcontextprotocol/sdk/server/mcp.js';
3
5
  import type { LikeC4LanguageServices } from '../LikeC4LanguageServices';
4
- export declare function elementResource<A extends Any = Any>(languageServices: LikeC4LanguageServices, el: ElementModel<A>, projectId?: aux.ProjectId<A>): {
5
- id: any;
6
- parent: {
7
- id: any;
8
- title: any;
9
- kind: any;
10
- } | null;
11
- projectId: any;
12
- title: any;
13
- kind: any;
14
- shape: any;
15
- technology: any;
16
- description: any;
17
- tags: any;
18
- children: any;
19
- relations: {
20
- incoming: any;
21
- outgoing: any;
22
- };
23
- views: any;
24
- sourceFile: import("../protocol").Locate.Res;
25
- };
26
- export declare function modelViewResource(languageServices: LikeC4LanguageServices, view: LikeC4ViewModel<aux.Any>, projectId?: ProjectId): {
27
- id: any;
28
- title: any;
29
- projectId: any;
30
- viewType: LikeC4ViewModel<aux.Any>;
31
- description: any;
32
- tags: any;
33
- nodes: any;
34
- sourceFile: import("../protocol").Locate.Res;
35
- };
6
+ export declare const logger: any;
7
+ type ToolResult<Out extends undefined | ZodRawShape = undefined> = Out extends ZodRawShape ? z.objectOutputType<Out, ZodTypeAny> : string;
8
+ type LikeC4ToolCallback<Args extends undefined | ZodRawShape, Out extends undefined | ZodRawShape> = Args extends ZodRawShape ? (languageServices: LikeC4LanguageServices, args: z.objectOutputType<Args, ZodTypeAny>, extra: RequestHandlerExtra<ServerRequest, ServerNotification>) => Promise<ToolResult<Out>> : (languageServices: LikeC4LanguageServices, extra: RequestHandlerExtra<ServerRequest, ServerNotification>) => Promise<ToolResult<Out>>;
9
+ export declare function likec4Tool<InputArgs extends ZodRawShape, OutputArgs extends ZodRawShape, Cb extends LikeC4ToolCallback<InputArgs, OutputArgs>>(config: {
10
+ name: string;
11
+ description?: string;
12
+ inputSchema?: InputArgs;
13
+ outputSchema?: OutputArgs;
14
+ annotations?: ToolAnnotations;
15
+ }, cb: Cb): (languageServices: LikeC4LanguageServices) => [string, {
16
+ inputSchema?: InputArgs;
17
+ }, ToolCallback<InputArgs>];
18
+ export {};
package/dist/mcp/utils.js CHANGED
@@ -1,104 +1,44 @@
1
- import { _type, imap, toArray } from "@likec4/core";
2
- export function elementResource(languageServices, el, projectId) {
3
- return {
4
- id: el.id,
5
- parent: !el.parent ? null : {
6
- id: el.parent.id,
7
- title: el.parent.title,
8
- kind: el.parent.kind
9
- },
10
- projectId,
11
- title: el.title,
12
- kind: el.kind,
13
- shape: el.shape,
14
- technology: el.technology,
15
- description: el.description,
16
- tags: el.tags,
17
- children: toArray(imap(el.children(), (c) => ({
18
- id: c.id,
19
- title: c.title,
20
- kind: el.kind
21
- }))),
22
- relations: {
23
- incoming: toArray(imap(el.incoming(), (r) => ({
24
- id: r.id,
25
- title: r.title,
26
- description: r.description,
27
- technology: r.technology,
28
- source: {
29
- id: r.source.id,
30
- title: r.source.title,
31
- kind: r.source.kind
32
- },
33
- ...r.target.id === el.id ? {
34
- type: "direct"
35
- } : {
36
- type: "implicit, to nested",
37
- target: {
38
- id: r.target.id,
39
- title: r.target.title,
40
- kind: r.target.kind
41
- }
42
- }
43
- }))),
44
- outgoing: toArray(imap(el.outgoing(), (r) => ({
45
- id: r.id,
46
- title: r.title,
47
- description: r.description,
48
- technology: r.technology,
49
- target: {
50
- id: r.target.id,
51
- title: r.target.title,
52
- kind: r.target.kind
53
- },
54
- ...r.source.id === el.id ? {
55
- type: "direct"
56
- } : {
57
- type: "implicit, from nested",
58
- source: {
59
- id: r.source.id,
60
- title: r.source.title,
61
- kind: r.source.kind
62
- }
63
- }
64
- })))
65
- },
66
- views: toArray(imap(el.views(), (v) => ({
67
- id: v.id,
68
- title: v.title
69
- }))),
70
- sourceFile: languageServices.locate({
71
- element: el.id,
72
- projectId
73
- })
74
- };
1
+ import { loggable } from "@likec4/log";
2
+ import { logger as mainLogger } from "../logger.js";
3
+ export const logger = mainLogger.getChild("mcp");
4
+ export function likec4Tool(config, cb) {
5
+ const { name, ...rest } = config;
6
+ return (languageServices) => [
7
+ name,
8
+ rest,
9
+ mkcallTool(name, languageServices, cb)
10
+ ];
75
11
  }
76
- export function modelViewResource(languageServices, view, projectId) {
77
- return {
78
- id: view.id,
79
- title: view.title,
80
- projectId,
81
- viewType: view[_type],
82
- description: view.$view.description ?? "",
83
- tags: view.tags,
84
- nodes: toArray(imap(view.nodes(), (node) => ({
85
- id: node.id,
86
- title: node.title,
87
- represents: node.element ? {
88
- element: node.element.id
89
- } : {}
90
- }))),
91
- sourceFile: languageServices.locate({
92
- view: view.id,
93
- projectId
94
- })
95
- // edges: toArray(imap(view.edges(), edge => ({
96
- // id: edge.id,
97
- // title: edge.title,
98
- // }))),
99
- // elements: toArray(imap(view.elements(), el => ({
100
- // id: el.id,
101
- // title: el.title,
102
- // }))),
12
+ function mkcallTool(name, languageServices, cb) {
13
+ const tool = cb.bind(null, languageServices);
14
+ return async function callTool(args, extra) {
15
+ logger.debug("Calling tool {name}", { name, args });
16
+ try {
17
+ const result = await tool.call(null, args, extra);
18
+ if (typeof result === "string") {
19
+ return {
20
+ content: [{
21
+ type: "text",
22
+ text: result
23
+ }]
24
+ };
25
+ }
26
+ return {
27
+ content: [{
28
+ type: "text",
29
+ text: JSON.stringify(result)
30
+ }],
31
+ structuredContent: result
32
+ };
33
+ } catch (err) {
34
+ logger.error(`Tool ${name} failed`, { err });
35
+ return {
36
+ content: [{
37
+ type: "text",
38
+ text: loggable(err)
39
+ }],
40
+ isError: true
41
+ };
42
+ }
103
43
  };
104
44
  }
@@ -102,8 +102,8 @@ export class MergedSpecification {
102
102
  },
103
103
  links: links ?? null,
104
104
  tags: tags ?? [],
105
- technology: technology ?? null,
106
- description: description ?? null,
105
+ ...technology && { technology },
106
+ ...description && { description },
107
107
  title,
108
108
  kind,
109
109
  id
@@ -155,6 +155,7 @@ export class MergedSpecification {
155
155
  };
156
156
  }
157
157
  if ("element" in parsed) {
158
+ logger.warn`Invalid ParsedAstDeployment ${parsed.id}, has both element and kind properties`;
158
159
  return null;
159
160
  }
160
161
  try {
@@ -166,10 +167,13 @@ export class MergedSpecification {
166
167
  let {
167
168
  technology = __kind.technology,
168
169
  notation = __kind.notation,
169
- style
170
+ style,
171
+ description,
172
+ ...rest
170
173
  } = parsed;
171
174
  return {
172
- ...parsed,
175
+ ...rest,
176
+ ...description && { description },
173
177
  ...notation && { notation },
174
178
  ...technology && { technology },
175
179
  style: {
@@ -3,3 +3,4 @@ export * from './fqn-index';
3
3
  export * from './model-builder';
4
4
  export * from './model-locator';
5
5
  export * from './model-parser';
6
+ export * from './parser/ValueConverter';
@@ -3,3 +3,4 @@ export * from "./fqn-index.js";
3
3
  export * from "./model-builder.js";
4
4
  export * from "./model-locator.js";
5
5
  export * from "./model-parser.js";
6
+ export * from "./parser/ValueConverter.js";
@@ -1,3 +1,4 @@
1
1
  import type * as c4 from '@likec4/core';
2
2
  import { ast } from '../ast';
3
3
  export declare function parseWhereClause(astNode: ast.WhereExpression): c4.WhereOperator;
4
+ export declare function createBinaryOperator(operator: Lowercase<ast.WhereBinaryExpression['operator']>, left: c4.WhereOperator, right: c4.WhereOperator | null): c4.WhereOperator;
@@ -45,32 +45,38 @@ export function parseWhereClause(astNode) {
45
45
  const left = parseWhereClause(astNode.left);
46
46
  const right = parseWhereClause(astNode.right);
47
47
  const operator = astNode.operator.toLowerCase();
48
- switch (operator) {
49
- case "and": {
50
- const operands = [
51
- isAndOperator(left) ? left.and : left,
52
- isAndOperator(right) ? right.and : right
53
- ].flat();
54
- invariant(isNonEmptyArray(operands), "Expected non-empty array");
55
- return {
56
- and: operands
57
- };
58
- }
59
- case "or": {
60
- const operands = [
61
- isOrOperator(left) ? left.or : left,
62
- isOrOperator(right) ? right.or : right
63
- ].flat();
64
- invariant(isNonEmptyArray(operands), "Expected non-empty array");
65
- return {
66
- or: operands
67
- };
68
- }
69
- default:
70
- nonexhaustive(operator);
71
- }
48
+ return createBinaryOperator(operator, left, right);
72
49
  }
73
50
  default:
74
51
  nonexhaustive(astNode);
75
52
  }
76
53
  }
54
+ export function createBinaryOperator(operator, left, right) {
55
+ if (right === null) {
56
+ return left;
57
+ }
58
+ switch (operator) {
59
+ case "and": {
60
+ const operands = [
61
+ isAndOperator(left) ? left.and : left,
62
+ isAndOperator(right) ? right.and : right
63
+ ].flat();
64
+ invariant(isNonEmptyArray(operands), "Expected non-empty array");
65
+ return {
66
+ and: operands
67
+ };
68
+ }
69
+ case "or": {
70
+ const operands = [
71
+ isOrOperator(left) ? left.or : left,
72
+ isOrOperator(right) ? right.or : right
73
+ ].flat();
74
+ invariant(isNonEmptyArray(operands), "Expected non-empty array");
75
+ return {
76
+ or: operands
77
+ };
78
+ }
79
+ default:
80
+ nonexhaustive(operator);
81
+ }
82
+ }