@likec4/language-server 1.40.0 → 1.42.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 (94) hide show
  1. package/browser/package.json +4 -0
  2. package/browser-worker/package.json +4 -0
  3. package/dist/LikeC4LanguageServices.d.ts +1 -1
  4. package/dist/LikeC4LanguageServices.mjs +3 -2
  5. package/dist/Rpc.mjs +30 -24
  6. package/dist/ast.d.ts +4 -9
  7. package/dist/ast.mjs +0 -10
  8. package/dist/bundled.mjs +4158 -3687
  9. package/dist/documentation/documentation-provider.mjs +1 -1
  10. package/dist/filesystem/FileSystemWatcher.d.ts +2 -2
  11. package/dist/filesystem/index.d.ts +1 -1
  12. package/dist/formatting/LikeC4Formatter.mjs +42 -10
  13. package/dist/formatting/utils.d.ts +3 -3
  14. package/dist/formatting/utils.mjs +1 -1
  15. package/dist/generated/ast.d.ts +40 -19
  16. package/dist/generated/ast.mjs +71 -26
  17. package/dist/generated/grammar.mjs +1 -1
  18. package/dist/logger.d.ts +1 -1
  19. package/dist/logger.mjs +3 -0
  20. package/dist/lsp/CompletionProvider.mjs +1 -1
  21. package/dist/lsp/DocumentLinkProvider.d.ts +1 -1
  22. package/dist/lsp/DocumentLinkProvider.mjs +1 -1
  23. package/dist/lsp/DocumentSymbolProvider.mjs +1 -1
  24. package/dist/lsp/HoverProvider.mjs +14 -2
  25. package/dist/mcp/NoopLikeC4MCPServer.d.ts +1 -1
  26. package/dist/mcp/NoopLikeC4MCPServer.mjs +1 -1
  27. package/dist/mcp/server/StdioLikeC4MCPServer.mjs +4 -1
  28. package/dist/mcp/server/StreamableLikeC4MCPServer.mjs +3 -3
  29. package/dist/mcp/server/WithMCPServer.mjs +2 -2
  30. package/dist/mcp/tools/_common.mjs +2 -2
  31. package/dist/model/builder/MergedSpecification.d.ts +3 -3
  32. package/dist/model/builder/MergedSpecification.mjs +37 -59
  33. package/dist/model/builder/buildModel.mjs +14 -17
  34. package/dist/model/model-builder.d.ts +1 -1
  35. package/dist/model/model-builder.mjs +12 -9
  36. package/dist/model/model-locator.d.ts +5 -0
  37. package/dist/model/model-locator.mjs +40 -3
  38. package/dist/model/model-parser-where.mjs +1 -2
  39. package/dist/model/model-parser.d.ts +91 -47
  40. package/dist/model/parser/Base.d.ts +13 -7
  41. package/dist/model/parser/Base.mjs +32 -21
  42. package/dist/model/parser/DeploymentModelParser.d.ts +9 -5
  43. package/dist/model/parser/DeploymentModelParser.mjs +49 -47
  44. package/dist/model/parser/DeploymentViewParser.d.ts +9 -5
  45. package/dist/model/parser/DeploymentViewParser.mjs +1 -2
  46. package/dist/model/parser/FqnRefParser.d.ts +12 -6
  47. package/dist/model/parser/FqnRefParser.mjs +28 -15
  48. package/dist/model/parser/GlobalsParser.d.ts +16 -7
  49. package/dist/model/parser/GlobalsParser.mjs +5 -3
  50. package/dist/model/parser/ImportsParser.d.ts +8 -5
  51. package/dist/model/parser/ImportsParser.mjs +4 -2
  52. package/dist/model/parser/ModelParser.d.ts +9 -5
  53. package/dist/model/parser/ModelParser.mjs +42 -42
  54. package/dist/model/parser/PredicatesParser.d.ts +9 -5
  55. package/dist/model/parser/SpecificationParser.d.ts +8 -5
  56. package/dist/model/parser/SpecificationParser.mjs +17 -23
  57. package/dist/model/parser/ValueConverter.mjs +1 -1
  58. package/dist/model/parser/ViewsParser.d.ts +20 -7
  59. package/dist/model/parser/ViewsParser.mjs +125 -35
  60. package/dist/model-change/ModelChanges.d.ts +1 -1
  61. package/dist/module.mjs +3 -2
  62. package/dist/protocol.d.ts +28 -4
  63. package/dist/references/scope-computation.mjs +2 -3
  64. package/dist/references/scope-provider.d.ts +2 -2
  65. package/dist/references/scope-provider.mjs +8 -15
  66. package/dist/test/testServices.d.ts +2 -0
  67. package/dist/test/testServices.mjs +32 -35
  68. package/dist/utils/disposable.mjs +2 -2
  69. package/dist/utils/index.mjs +1 -1
  70. package/dist/validation/_shared.d.ts +1 -1
  71. package/dist/validation/deployment-checks.d.ts +1 -1
  72. package/dist/validation/deployment-checks.mjs +4 -1
  73. package/dist/validation/dynamic-view.d.ts +3 -2
  74. package/dist/validation/dynamic-view.mjs +21 -2
  75. package/dist/validation/element-ref.d.ts +2 -2
  76. package/dist/validation/element-ref.mjs +1 -1
  77. package/dist/validation/imports.d.ts +0 -1
  78. package/dist/validation/imports.mjs +0 -5
  79. package/dist/validation/index.d.ts +1 -1
  80. package/dist/validation/index.mjs +19 -13
  81. package/dist/validation/view-predicates/relation-with.d.ts +1 -1
  82. package/dist/validation/view.d.ts +1 -1
  83. package/dist/view-utils/index.d.ts +0 -1
  84. package/dist/view-utils/index.mjs +0 -1
  85. package/dist/views/likec4-views.d.ts +6 -0
  86. package/dist/views/likec4-views.mjs +31 -18
  87. package/dist/workspace/ProjectsManager.d.ts +23 -31
  88. package/dist/workspace/ProjectsManager.mjs +78 -89
  89. package/dist/workspace/WorkspaceManager.mjs +1 -1
  90. package/likec4lib/package.json +4 -0
  91. package/package.json +25 -29
  92. package/protocol/package.json +4 -0
  93. package/dist/view-utils/resolve-relative-paths.d.ts +0 -2
  94. package/dist/view-utils/resolve-relative-paths.mjs +0 -78
package/dist/logger.d.ts CHANGED
@@ -1,6 +1,7 @@
1
1
  import { type Logger, type Sink, type TextFormatter } from '@likec4/log';
2
2
  import type { Connection } from 'vscode-languageserver';
3
3
  export declare const logger: Logger;
4
+ export { logger as serverLogger, };
4
5
  export declare function logError(err: unknown): void;
5
6
  /**
6
7
  * Logs an error as warning (not critical)
@@ -14,4 +15,3 @@ type LspConnectionSinkProps = {
14
15
  };
15
16
  export declare function getLspConnectionSink(connection: Connection, props?: LspConnectionSinkProps): Sink;
16
17
  export declare function getTelemetrySink(connection: Connection): Sink;
17
- export {};
package/dist/logger.mjs CHANGED
@@ -7,6 +7,9 @@ import {
7
7
  logger as root
8
8
  } from "@likec4/log";
9
9
  export const logger = root.getChild("server");
10
+ export {
11
+ logger as serverLogger
12
+ };
10
13
  export function logError(err) {
11
14
  logger.error(loggable(err));
12
15
  }
@@ -1,4 +1,4 @@
1
- import { ThemeColors } from "@likec4/core";
1
+ import { ThemeColors } from "@likec4/core/styles";
2
2
  import { AstUtils } from "langium";
3
3
  import {
4
4
  DefaultCompletionProvider
@@ -5,7 +5,7 @@ import type { LikeC4Services } from '../module';
5
5
  export declare class LikeC4DocumentLinkProvider implements DocumentLinkProvider {
6
6
  private services;
7
7
  constructor(services: LikeC4Services);
8
- getDocumentLinks(doc: LangiumDocument, _params: DocumentLinkParams, cancelToken?: CancellationToken): Promise<DocumentLink[]>;
8
+ getDocumentLinks(doc: LangiumDocument, _params: DocumentLinkParams, _cancelToken?: CancellationToken): Promise<DocumentLink[]>;
9
9
  resolveLink(doc: LangiumDocument, link: string): string;
10
10
  relativeLink(doc: LangiumDocument, link: string): string | null;
11
11
  }
@@ -6,7 +6,7 @@ export class LikeC4DocumentLinkProvider {
6
6
  constructor(services) {
7
7
  this.services = services;
8
8
  }
9
- async getDocumentLinks(doc, _params, cancelToken) {
9
+ async getDocumentLinks(doc, _params, _cancelToken) {
10
10
  if (!isLikeC4LangiumDocument(doc) || this.services.likec4.LanguageServices.isExcluded(doc)) {
11
11
  return [];
12
12
  }
@@ -269,7 +269,7 @@ export class LikeC4DocumentSymbolProvider {
269
269
  const doc = AstUtils.getDocument(astElement);
270
270
  const instance = this.parser.forDocument(doc).parseDeployedInstance(astElement);
271
271
  const name = this.nameProvider.getNameStrict(astElement);
272
- const detail = "instance of " + instance.element;
272
+ const detail = "instance of " + instance.element.model;
273
273
  return [
274
274
  {
275
275
  kind: this.symbolKind(astElement),
@@ -1,4 +1,4 @@
1
- import { FqnRef } from "@likec4/core";
1
+ import { FqnRef, preferSummary } from "@likec4/core";
2
2
  import { AstUtils } from "langium";
3
3
  import { AstNodeHoverProvider } from "langium/lsp";
4
4
  import { ast } from "../ast.mjs";
@@ -27,6 +27,10 @@ export class LikeC4HoverProvider extends AstNodeHoverProvider {
27
27
  lines.push(`### ${el.title}`);
28
28
  }
29
29
  lines.push("deployment node `" + el.kind + "` ");
30
+ const summary = preferSummary(el);
31
+ if (summary) {
32
+ lines.push("", summary.md ?? summary.txt);
33
+ }
30
34
  return {
31
35
  contents: {
32
36
  kind: "markdown",
@@ -79,7 +83,15 @@ export class LikeC4HoverProvider extends AstNodeHoverProvider {
79
83
  if (!el) {
80
84
  return;
81
85
  }
82
- const lines = [el.id, `### ${el.title}`, "element kind `" + el.kind + "` "];
86
+ const lines = [
87
+ el.id,
88
+ `### ${el.title}`,
89
+ "element kind `" + el.kind + "` "
90
+ ];
91
+ const summary = preferSummary(el);
92
+ if (summary) {
93
+ lines.push("", summary.md ?? summary.txt);
94
+ }
83
95
  return {
84
96
  contents: {
85
97
  kind: "markdown",
@@ -4,6 +4,6 @@ export declare class NoopLikeC4MCPServer implements LikeC4MCPServer {
4
4
  get mcp(): McpServer;
5
5
  get isStarted(): boolean;
6
6
  get port(): number;
7
- start(port: number): Promise<void>;
7
+ start(): Promise<void>;
8
8
  stop(): Promise<void>;
9
9
  }
@@ -8,7 +8,7 @@ export class NoopLikeC4MCPServer {
8
8
  get port() {
9
9
  return NaN;
10
10
  }
11
- start(port) {
11
+ start() {
12
12
  return Promise.resolve();
13
13
  }
14
14
  stop() {
@@ -37,7 +37,10 @@ export class StdioLikeC4MCPServer {
37
37
  }
38
38
  logger.info("Stopping MCP stdio server");
39
39
  await this.transport.close();
40
- this._mcp?.close();
40
+ if (this._mcp) {
41
+ await this._mcp.close();
42
+ }
43
+ this._mcp = void 0;
41
44
  this.transport = void 0;
42
45
  }
43
46
  }
@@ -47,10 +47,10 @@ export class StreamableLikeC4MCPServer {
47
47
  };
48
48
  await server.connect(transport);
49
49
  await transport.handleRequest(req, res, await c.req.json());
50
- res.on("close", () => {
50
+ res.on("close", async () => {
51
51
  logger.debug("Request closed");
52
- transport.close();
53
- server.close();
52
+ await transport.close();
53
+ await server.close();
54
54
  });
55
55
  return toFetchResponse(res);
56
56
  } catch (e) {
@@ -19,10 +19,10 @@ const streamableLikeC4MCPServer = (services, defaultPort = 33335) => {
19
19
  port = defaultPort
20
20
  } = update.configuration.mcp;
21
21
  if (!enabled) {
22
- server.stop();
22
+ void server.stop();
23
23
  return;
24
24
  }
25
- Promise.resolve().then(() => server.start(port)).then(() => {
25
+ void Promise.resolve().then(() => server.start(port)).then(() => {
26
26
  connection?.telemetry?.logEvent({
27
27
  eventName: "mcp-server-started",
28
28
  mcpPort: port
@@ -15,7 +15,7 @@ export const locationSchema = z.object({
15
15
  })
16
16
  }).describe("Range in the file")
17
17
  }).nullable();
18
- export const projectIdSchema = z.string().refine((v) => true).optional().default(ProjectsManager.DefaultProjectId).describe('Project id (optional, will use "default" if not specified)');
18
+ export const projectIdSchema = z.string().refine((_v) => true).optional().default(ProjectsManager.DefaultProjectId).describe('Project id (optional, will use "default" if not specified)');
19
19
  export const includedInViewsSchema = z.array(z.object({
20
20
  id: z.string().describe("View id"),
21
21
  title: z.string().describe("View title"),
@@ -36,7 +36,7 @@ export const mkLocate = (languageServices, projectId) => (params) => {
36
36
  range: loc.range
37
37
  } : null;
38
38
  } catch (e) {
39
- logger.debug(`Failed to locate ${params}`, { error: e });
39
+ logger.debug(`Failed to locate {params}`, { error: e, params });
40
40
  return null;
41
41
  }
42
42
  };
@@ -16,11 +16,11 @@ export declare class MergedSpecification {
16
16
  /**
17
17
  * Converts a parsed model into a C4 model element.
18
18
  */
19
- toModelElement: ({ tags, links, style: { color, shape, icon, opacity, border, size, multiple, padding, textSize, }, id, kind, title, description, technology, metadata, }: ParsedAstElement) => c4.Element | null;
19
+ toModelElement: ({ tags, links, style, id, kind, title, description, technology, summary, metadata, }: ParsedAstElement) => c4.Element | null;
20
20
  /**
21
21
  * Converts a parsed model into a C4 model relation.
22
22
  */
23
- toModelRelation: ({ astPath, source, target, kind, links, id, ...model }: ParsedAstRelation) => c4.Relationship | null;
23
+ toModelRelation: ({ astPath: _astPath, source, target, kind, links, id, ...model }: ParsedAstRelation) => c4.Relationship | null;
24
24
  /**
25
25
  * Converts a parsed deployment model into a C4 deployment model
26
26
  */
@@ -28,5 +28,5 @@ export declare class MergedSpecification {
28
28
  /**
29
29
  * Converts a parsed deployment relation into a C4 deployment relation.
30
30
  */
31
- toDeploymentRelation: ({ astPath, source, target, kind, links, id, ...model }: ParsedAstDeploymentRelation) => c4.DeploymentRelationship | null;
31
+ toDeploymentRelation: ({ astPath: _astPath, source, target, kind, links, id, ...model }: ParsedAstDeploymentRelation) => c4.DeploymentRelationship | null;
32
32
  }
@@ -1,10 +1,9 @@
1
- import { FqnRef } from "@likec4/core/types";
2
- import { MultiMap, nameFromFqn } from "@likec4/core/utils";
1
+ import { exact, FqnRef } from "@likec4/core/types";
2
+ import { isNonEmptyArray, MultiMap, nameFromFqn } from "@likec4/core/utils";
3
3
  import {
4
- isBoolean,
5
4
  isEmpty,
6
5
  isNonNullish,
7
- isNumber
6
+ unique
8
7
  } from "remeda";
9
8
  import { logger, logWarnError } from "../../logger.mjs";
10
9
  import { assignTagColors } from "./assignTagColors.mjs";
@@ -50,22 +49,13 @@ export class MergedSpecification {
50
49
  toModelElement = ({
51
50
  tags,
52
51
  links,
53
- style: {
54
- color,
55
- shape,
56
- icon,
57
- opacity,
58
- border,
59
- size,
60
- multiple,
61
- padding,
62
- textSize
63
- },
52
+ style,
64
53
  id,
65
54
  kind,
66
55
  title,
67
56
  description,
68
57
  technology,
58
+ summary,
69
59
  metadata
70
60
  }) => {
71
61
  try {
@@ -74,41 +64,33 @@ export class MergedSpecification {
74
64
  logger.warn`No kind '${kind}' found for ${id}`;
75
65
  return null;
76
66
  }
77
- color ??= __kind.style.color;
78
- shape ??= __kind.style.shape;
79
- icon ??= __kind.style.icon;
80
- opacity ??= __kind.style.opacity;
81
- border ??= __kind.style.border;
82
67
  technology ??= __kind.technology;
83
- multiple ??= __kind.style.multiple;
84
- size ??= __kind.style.size;
85
- padding ??= __kind.style.padding;
86
- textSize ??= __kind.style.textSize;
87
68
  description ??= __kind.description;
69
+ summary ??= __kind.summary;
88
70
  links ??= __kind.links;
89
71
  title = title === nameFromFqn(id) && __kind.title ? __kind.title : title;
90
- return {
91
- ...color && { color },
92
- ...shape && { shape },
93
- ...icon && { icon },
94
- ...metadata && !isEmpty(metadata) && { metadata },
95
- ...__kind.notation && { notation: __kind.notation },
96
- style: {
97
- ...border && { border },
98
- ...size && { size },
99
- ...padding && { padding },
100
- ...textSize && { textSize },
101
- ...isBoolean(multiple) && { multiple },
102
- ...isNumber(opacity) && { opacity }
103
- },
104
- links: links ?? null,
105
- tags: tags ?? [],
106
- ...technology && { technology },
107
- ...description && { description },
72
+ if (__kind.tags && isNonEmptyArray(__kind.tags)) {
73
+ tags = tags ? unique([
74
+ ...__kind.tags,
75
+ ...tags
76
+ ]) : __kind.tags;
77
+ }
78
+ return exact({
79
+ metadata: metadata && !isEmpty(metadata) ? metadata : void 0,
80
+ notation: __kind.notation,
81
+ style: exact({
82
+ ...__kind.style,
83
+ ...style
84
+ }),
85
+ links,
86
+ tags,
87
+ summary,
88
+ technology,
89
+ description,
108
90
  title,
109
91
  kind,
110
92
  id
111
- };
93
+ });
112
94
  } catch (e) {
113
95
  logWarnError(e);
114
96
  }
@@ -118,7 +100,8 @@ export class MergedSpecification {
118
100
  * Converts a parsed model into a C4 model relation.
119
101
  */
120
102
  toModelRelation = ({
121
- astPath,
103
+ astPath: _astPath,
104
+ // omit
122
105
  source,
123
106
  target,
124
107
  kind,
@@ -166,28 +149,22 @@ export class MergedSpecification {
166
149
  return null;
167
150
  }
168
151
  let {
169
- technology = __kind.technology,
170
- notation = __kind.notation,
152
+ id,
171
153
  style,
172
154
  title,
173
- description,
174
155
  ...rest
175
156
  } = parsed;
176
- description ??= __kind.description;
177
157
  title = title === nameFromFqn(parsed.id) && __kind.title ? __kind.title : title;
178
- return {
158
+ return exact({
159
+ ...__kind,
179
160
  ...rest,
180
- ...{ title },
181
- ...description && { description },
182
- ...notation && { notation },
183
- ...technology && { technology },
184
- style: {
185
- border: "dashed",
186
- opacity: 10,
161
+ title,
162
+ style: exact({
187
163
  ...__kind.style,
188
164
  ...style
189
- }
190
- };
165
+ }),
166
+ id
167
+ });
191
168
  } catch (e) {
192
169
  logWarnError(e);
193
170
  }
@@ -197,7 +174,8 @@ export class MergedSpecification {
197
174
  * Converts a parsed deployment relation into a C4 deployment relation.
198
175
  */
199
176
  toDeploymentRelation = ({
200
- astPath,
177
+ astPath: _astPath,
178
+ // omit
201
179
  source,
202
180
  target,
203
181
  kind,
@@ -1,15 +1,16 @@
1
1
  import {
2
- computeColorValues,
3
2
  isDeploymentNode,
4
3
  isGlobalFqn
5
4
  } from "@likec4/core";
6
5
  import { resolveRulesExtendedViews } from "@likec4/core/compute-view";
7
- import { _stage, _type, FqnRef } from "@likec4/core/types";
6
+ import { computeColorValues } from "@likec4/core/styles";
7
+ import { _stage, _type, exact, FqnRef, isExtendsElementView } from "@likec4/core/types";
8
8
  import {
9
9
  compareNatural,
10
10
  parentFqn,
11
11
  sortByFqnHierarchically
12
12
  } from "@likec4/core/utils";
13
+ import { UriUtils } from "langium";
13
14
  import {
14
15
  filter,
15
16
  flatMap,
@@ -27,7 +28,6 @@ import {
27
28
  reduce
28
29
  } from "remeda";
29
30
  import { logger } from "../../logger.mjs";
30
- import { resolveRelativePaths } from "../../view-utils/index.mjs";
31
31
  import { MergedExtends } from "./MergedExtends.mjs";
32
32
  import { MergedSpecification } from "./MergedSpecification.mjs";
33
33
  export function buildModelData(project, docs) {
@@ -156,6 +156,7 @@ export function buildModelData(project, docs) {
156
156
  return {
157
157
  ...omitBy(model, (v) => v === void 0),
158
158
  [_stage]: "parsed",
159
+ sourcePath: UriUtils.relative(project.folderUri, docUri),
159
160
  docUri,
160
161
  description,
161
162
  title,
@@ -163,12 +164,7 @@ export function buildModelData(project, docs) {
163
164
  };
164
165
  };
165
166
  }
166
- const parsedViews = pipe(
167
- docs,
168
- flatMap((d) => map(d.c4Views, toC4View(d))),
169
- // Resolve relative paths and sort by
170
- resolveRelativePaths
171
- );
167
+ const parsedViews = docs.flatMap((d) => map(d.c4Views, toC4View(d)));
172
168
  if (!parsedViews.some((v) => v.id === "index")) {
173
169
  parsedViews.unshift({
174
170
  [_stage]: "parsed",
@@ -176,8 +172,6 @@ export function buildModelData(project, docs) {
176
172
  id: "index",
177
173
  title: "Landscape view",
178
174
  description: null,
179
- tags: null,
180
- links: null,
181
175
  rules: [
182
176
  {
183
177
  include: [
@@ -189,19 +183,22 @@ export function buildModelData(project, docs) {
189
183
  ]
190
184
  });
191
185
  }
192
- const views = pipe(
186
+ let views = pipe(
193
187
  parsedViews,
194
- indexBy(prop("id")),
195
- resolveRulesExtendedViews
188
+ indexBy(prop("id"))
196
189
  );
190
+ if (parsedViews.some(isExtendsElementView)) {
191
+ views = resolveRulesExtendedViews(views);
192
+ }
197
193
  return {
198
194
  data: {
199
195
  [_stage]: "parsed",
200
196
  projectId: project.id,
201
- project: {
197
+ project: exact({
202
198
  id: project.id,
203
- title: project.config.title ?? project.config.name
204
- },
199
+ title: project.config.title ?? project.config.name,
200
+ styles: project.config.styles
201
+ }),
205
202
  specification: {
206
203
  tags: c4Specification.tags,
207
204
  elements: c4Specification.specs.elements,
@@ -1,6 +1,6 @@
1
- import * as c4 from '@likec4/core';
2
1
  import { type ViewId } from '@likec4/core';
3
2
  import { LikeC4Model } from '@likec4/core/model';
3
+ import type * as c4 from '@likec4/core/types';
4
4
  import { type URI, Disposable } from 'langium';
5
5
  import { CancellationToken } from 'vscode-jsonrpc';
6
6
  import type { LikeC4Services } from '../module';
@@ -1,5 +1,5 @@
1
- import * as c4 from "@likec4/core";
2
1
  import {
2
+ _stage,
3
3
  isScopedElementView
4
4
  } from "@likec4/core";
5
5
  import { computeView } from "@likec4/core/compute-view";
@@ -22,7 +22,6 @@ import {
22
22
  prop,
23
23
  values
24
24
  } from "remeda";
25
- import { CancellationToken } from "vscode-jsonrpc";
26
25
  import { isLikeC4Builtin } from "../likec4lib.mjs";
27
26
  import { logger as mainLogger, logWarnError } from "../logger.mjs";
28
27
  import { ADisposable, performanceMark } from "../utils/index.mjs";
@@ -132,7 +131,7 @@ export class DefaultLikeC4ModelBuilder extends ADisposable {
132
131
  return LikeC4Model.create(parsedData);
133
132
  });
134
133
  }
135
- async parseModel(projectId, cancelToken = CancellationToken.None) {
134
+ async parseModel(projectId, cancelToken) {
136
135
  const project = this.projects.ensureProjectId(projectId);
137
136
  const logger = builderLogger.getChild(project);
138
137
  const cache = this.cache;
@@ -143,7 +142,9 @@ export class DefaultLikeC4ModelBuilder extends ADisposable {
143
142
  }
144
143
  const t0 = performanceMark();
145
144
  return await this.mutex.read(async () => {
146
- await interruptAndCheck(cancelToken);
145
+ if (cancelToken) {
146
+ await interruptAndCheck(cancelToken);
147
+ }
147
148
  const result = this.unsafeSyncJoinedModelData(project);
148
149
  logger.debug`parseModel in ${t0.pretty}`;
149
150
  return result;
@@ -178,18 +179,18 @@ export class DefaultLikeC4ModelBuilder extends ADisposable {
178
179
  const key = computedViewKey(projectId, v.id);
179
180
  const previous = this.previousViews[key];
180
181
  const view = previous && eq(v, previous) ? previous : v;
182
+ this.previousViews[key] = view;
181
183
  viewsCache.set(key, view);
182
184
  return [v.id, view];
183
185
  });
184
- this.previousViews = { ...this.previousViews, ...views };
185
186
  return LikeC4Model.create({
186
187
  ...parsedModel.$data,
187
- [c4._stage]: "computed",
188
+ [_stage]: "computed",
188
189
  views
189
190
  });
190
191
  });
191
192
  }
192
- async buildLikeC4Model(projectId, cancelToken = CancellationToken.None) {
193
+ async buildLikeC4Model(projectId, cancelToken) {
193
194
  const project = this.projects.ensureProjectId(projectId);
194
195
  const logger = builderLogger.getChild(project);
195
196
  const cache = this.cache;
@@ -200,13 +201,15 @@ export class DefaultLikeC4ModelBuilder extends ADisposable {
200
201
  }
201
202
  const t0 = performanceMark();
202
203
  return await this.mutex.read(async () => {
203
- await interruptAndCheck(cancelToken);
204
+ if (cancelToken) {
205
+ await interruptAndCheck(cancelToken);
206
+ }
204
207
  const result = this.unsafeSyncBuildModel(project);
205
208
  logger.debug(`buildLikeC4Model in ${t0.pretty}`);
206
209
  return result;
207
210
  });
208
211
  }
209
- async computeView(viewId, projectId, cancelToken = CancellationToken.None) {
212
+ async computeView(viewId, projectId, cancelToken) {
210
213
  const project = this.projects.ensureProjectId(projectId);
211
214
  const logger = builderLogger.getChild(project);
212
215
  const cache = this.cache;
@@ -30,4 +30,9 @@ export declare class LikeC4ModelLocator {
30
30
  range: Range;
31
31
  isSpecification: boolean;
32
32
  }>>;
33
+ locateDynamicViewStep(params: {
34
+ view: c4.ViewId;
35
+ astPath: string;
36
+ projectId?: c4.ProjectId | undefined;
37
+ }): Location | null;
33
38
  }
@@ -95,9 +95,10 @@ export class LikeC4ModelLocator {
95
95
  if (!ast.isRelation(node) && !ast.isDeploymentRelation(node)) {
96
96
  continue;
97
97
  }
98
- let targetNode = node.title ? findNodeForProperty(node.$cstNode, "title") : void 0;
99
- targetNode ??= node.kind ? findNodeForProperty(node.$cstNode, "kind") : void 0;
98
+ let targetNode = node.kind ? findNodeForProperty(node.$cstNode, "kind") : void 0;
99
+ targetNode ??= node.dotKind ? findNodeForProperty(node.$cstNode, "dotKind") : void 0;
100
100
  targetNode ??= findNodeForKeyword(node.$cstNode, "->");
101
+ targetNode ??= findNodeForProperty(node.$cstNode, "title");
101
102
  targetNode ??= findNodeForProperty(node.$cstNode, "target");
102
103
  targetNode ??= node.$cstNode;
103
104
  if (!targetNode) {
@@ -105,7 +106,10 @@ export class LikeC4ModelLocator {
105
106
  }
106
107
  return {
107
108
  uri: doc.uri.toString(),
108
- range: targetNode.range
109
+ range: {
110
+ start: targetNode.range.start,
111
+ end: targetNode.range.start
112
+ }
109
113
  };
110
114
  }
111
115
  return null;
@@ -199,4 +203,37 @@ export class LikeC4ModelLocator {
199
203
  return [];
200
204
  }
201
205
  }
206
+ locateDynamicViewStep(params) {
207
+ const { doc, viewAst } = this.locateViewAst(params.view, params.projectId) ?? {};
208
+ if (!doc || !viewAst) {
209
+ return null;
210
+ }
211
+ if (!ast.isDynamicView(viewAst) || !viewAst.body) {
212
+ logger.warn(`View ${params.view} is not a dynamic view`);
213
+ return null;
214
+ }
215
+ const astPath = this.services.workspace.AstNodeLocator.getAstNodePath(viewAst.body) + params.astPath;
216
+ const node = this.services.workspace.AstNodeLocator.getAstNode(doc.parseResult.value, astPath);
217
+ if (!node || !ast.isDynamicViewStep(node)) {
218
+ logger.warn(`Failed to locate dynamic view step ${astPath} in view ${params.view}`);
219
+ return null;
220
+ }
221
+ let targetNode = node.kind ? findNodeForProperty(node.$cstNode, "kind") : void 0;
222
+ targetNode ??= node.dotKind ? findNodeForProperty(node.$cstNode, "dotKind") : void 0;
223
+ targetNode ??= findNodeForKeyword(node.$cstNode, "->");
224
+ targetNode ??= findNodeForKeyword(node.$cstNode, "<-");
225
+ targetNode ??= findNodeForProperty(node.$cstNode, "title");
226
+ targetNode ??= findNodeForProperty(node.$cstNode, "target");
227
+ targetNode ??= node.$cstNode;
228
+ if (!targetNode) {
229
+ return null;
230
+ }
231
+ return {
232
+ uri: doc.uri.toString(),
233
+ range: {
234
+ start: targetNode.range.start,
235
+ end: targetNode.range.start
236
+ }
237
+ };
238
+ }
202
239
  }
@@ -1,5 +1,4 @@
1
- import { invariant, isNonEmptyArray, nonexhaustive } from "@likec4/core";
2
- import { isAndOperator, isOrOperator } from "@likec4/core";
1
+ import { invariant, isAndOperator, isNonEmptyArray, isOrOperator, nonexhaustive } from "@likec4/core";
3
2
  import { ast } from "../ast.mjs";
4
3
  const parseEquals = ({ operator, not }, value) => {
5
4
  if (operator.startsWith("!=")) {