@likec4/language-server 1.25.0 → 1.26.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.
- package/bin/likec4-language-server.mjs +1 -1
- package/dist/LikeC4FileSystem.js +6 -1
- package/dist/LikeC4LanguageServices.d.ts +77 -0
- package/dist/LikeC4LanguageServices.js +118 -0
- package/dist/Rpc.js +106 -28
- package/dist/ast.d.ts +10 -0
- package/dist/bundled.mjs +2352 -2278
- package/dist/config/index.d.ts +1 -0
- package/dist/config/index.js +1 -0
- package/dist/config/schema.d.ts +8 -0
- package/dist/config/schema.js +19 -0
- package/dist/index.d.ts +1 -0
- package/dist/lsp/CodeLensProvider.js +3 -1
- package/dist/model/builder/buildModel.d.ts +8 -1
- package/dist/model/deployments-index.js +1 -1
- package/dist/model/fqn-index.d.ts +9 -6
- package/dist/model/fqn-index.js +24 -14
- package/dist/model/model-builder.d.ts +16 -6
- package/dist/model/model-builder.js +64 -50
- package/dist/model/model-locator.d.ts +11 -10
- package/dist/model/model-locator.js +32 -14
- package/dist/model/model-parser.d.ts +148 -148
- package/dist/model/model-parser.js +2 -2
- package/dist/model/parser/ModelParser.js +14 -2
- package/dist/model-change/ModelChanges.d.ts +1 -1
- package/dist/model-change/ModelChanges.js +2 -2
- package/dist/module.d.ts +9 -3
- package/dist/module.js +19 -5
- package/dist/protocol.d.ts +98 -16
- package/dist/protocol.js +21 -6
- package/dist/references/scope-provider.d.ts +24 -11
- package/dist/references/scope-provider.js +97 -68
- package/dist/shared/index.d.ts +0 -1
- package/dist/shared/index.js +0 -1
- package/dist/test/testServices.d.ts +15 -1
- package/dist/test/testServices.js +65 -17
- package/dist/utils/index.d.ts +3 -0
- package/dist/utils/index.js +3 -0
- package/dist/utils/projectId.d.ts +3 -0
- package/dist/utils/projectId.js +6 -0
- package/dist/validation/deployment-checks.js +5 -2
- package/dist/validation/element.js +2 -1
- package/dist/validation/specification.js +14 -7
- package/dist/validation/view.js +10 -8
- package/dist/views/index.d.ts +1 -1
- package/dist/views/index.js +1 -1
- package/dist/views/likec4-views.d.ts +17 -8
- package/dist/views/likec4-views.js +12 -11
- package/dist/workspace/AstNodeDescriptionProvider.d.ts +7 -0
- package/dist/workspace/AstNodeDescriptionProvider.js +18 -0
- package/dist/workspace/IndexManager.d.ts +10 -0
- package/dist/workspace/IndexManager.js +17 -0
- package/dist/workspace/LangiumDocuments.d.ts +14 -0
- package/dist/workspace/LangiumDocuments.js +31 -0
- package/dist/workspace/ProjectsManager.d.ts +48 -0
- package/dist/workspace/ProjectsManager.js +150 -0
- package/dist/{shared → workspace}/WorkspaceManager.d.ts +8 -2
- package/dist/{shared → workspace}/WorkspaceManager.js +22 -0
- package/dist/workspace/index.d.ts +5 -0
- package/dist/workspace/index.js +5 -0
- package/package.json +21 -12
package/dist/LikeC4FileSystem.js
CHANGED
|
@@ -4,10 +4,15 @@ import { NodeFileSystemProvider } from "langium/node";
|
|
|
4
4
|
import { LikeC4LanguageMetaData } from "./generated/module.js";
|
|
5
5
|
import { Content, isLikeC4Builtin } from "./likec4lib.js";
|
|
6
6
|
import { logError } from "./logger.js";
|
|
7
|
+
import { ProjectsManager } from "./workspace/ProjectsManager.js";
|
|
7
8
|
export const LikeC4FileSystem = {
|
|
8
9
|
fileSystemProvider: () => new SymLinkTraversingFileSystemProvider()
|
|
9
10
|
};
|
|
10
|
-
const
|
|
11
|
+
const SearchExtension = [
|
|
12
|
+
...LikeC4LanguageMetaData.fileExtensions,
|
|
13
|
+
...ProjectsManager.ConfigFileNames
|
|
14
|
+
];
|
|
15
|
+
const hasExtension = (path) => SearchExtension.some((ext) => path.endsWith(ext));
|
|
11
16
|
class SymLinkTraversingFileSystemProvider extends NodeFileSystemProvider {
|
|
12
17
|
async readFile(uri) {
|
|
13
18
|
if (isLikeC4Builtin(uri)) {
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
import { type DiagramView, type NonEmptyArray, type ProjectId, LikeC4Model } from '@likec4/core';
|
|
2
|
+
import { URI } from 'langium';
|
|
3
|
+
import { type Range } from 'vscode-languageserver-types';
|
|
4
|
+
import type { ProjectConfig } from './config';
|
|
5
|
+
import type { LikeC4ModelBuilder } from './model';
|
|
6
|
+
import type { LikeC4Services } from './module';
|
|
7
|
+
import type { LikeC4Views } from './views/likec4-views';
|
|
8
|
+
export interface LikeC4LanguageServices {
|
|
9
|
+
readonly views: LikeC4Views;
|
|
10
|
+
readonly builder: LikeC4ModelBuilder;
|
|
11
|
+
readonly workspaceUri: URI;
|
|
12
|
+
projects(): NonEmptyArray<{
|
|
13
|
+
id: ProjectId;
|
|
14
|
+
folder: URI;
|
|
15
|
+
config: ProjectConfig;
|
|
16
|
+
documents: NonEmptyArray<URI> | null;
|
|
17
|
+
}>;
|
|
18
|
+
diagrams(): Promise<DiagramView[]>;
|
|
19
|
+
computedModel(project?: ProjectId | undefined): Promise<LikeC4Model.Computed>;
|
|
20
|
+
layoutedModel(project?: ProjectId | undefined): Promise<LikeC4Model.Layouted>;
|
|
21
|
+
getErrors(): Array<{
|
|
22
|
+
message: string;
|
|
23
|
+
line: number;
|
|
24
|
+
range: Range;
|
|
25
|
+
sourceFsPath: string;
|
|
26
|
+
}>;
|
|
27
|
+
notifyUpdate(update: {
|
|
28
|
+
changed?: string;
|
|
29
|
+
removed?: string;
|
|
30
|
+
}): Promise<boolean>;
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* Public Language Services
|
|
34
|
+
*/
|
|
35
|
+
export declare class DefaultLikeC4LanguageServices implements LikeC4LanguageServices {
|
|
36
|
+
private services;
|
|
37
|
+
readonly views: LikeC4Views;
|
|
38
|
+
readonly builder: LikeC4ModelBuilder;
|
|
39
|
+
private projectsManager;
|
|
40
|
+
constructor(services: LikeC4Services);
|
|
41
|
+
get workspaceUri(): URI;
|
|
42
|
+
projects(): NonEmptyArray<{
|
|
43
|
+
id: ProjectId;
|
|
44
|
+
folder: URI;
|
|
45
|
+
config: ProjectConfig;
|
|
46
|
+
documents: NonEmptyArray<URI> | null;
|
|
47
|
+
}>;
|
|
48
|
+
/**
|
|
49
|
+
* Diagram is a computed view, layouted using Graphviz
|
|
50
|
+
* Used in React components
|
|
51
|
+
*/
|
|
52
|
+
diagrams(): Promise<DiagramView[]>;
|
|
53
|
+
/**
|
|
54
|
+
* Builds LikeC4Model from all documents
|
|
55
|
+
* Only computes view predicates {@link ComputedView} - i.e. no layout
|
|
56
|
+
* Not ready for rendering, but enough to traverse
|
|
57
|
+
*/
|
|
58
|
+
computedModel(project?: ProjectId | undefined): Promise<LikeC4Model.Computed>;
|
|
59
|
+
/**
|
|
60
|
+
* Same as {@link computedModel()}, but also applies layout
|
|
61
|
+
* Ready for rendering
|
|
62
|
+
*/
|
|
63
|
+
layoutedModel(project?: ProjectId | undefined): Promise<LikeC4Model.Layouted>;
|
|
64
|
+
getErrors(): Array<{
|
|
65
|
+
message: string;
|
|
66
|
+
line: number;
|
|
67
|
+
range: Range;
|
|
68
|
+
sourceFsPath: string;
|
|
69
|
+
}>;
|
|
70
|
+
/**
|
|
71
|
+
* TODO Replace with watcher
|
|
72
|
+
*/
|
|
73
|
+
notifyUpdate({ changed, removed }: {
|
|
74
|
+
changed?: string;
|
|
75
|
+
removed?: string;
|
|
76
|
+
}): Promise<boolean>;
|
|
77
|
+
}
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
import { LikeC4Model } from "@likec4/core";
|
|
2
|
+
import { loggable } from "@likec4/log";
|
|
3
|
+
import { URI } from "langium";
|
|
4
|
+
import { entries, hasAtLeast, indexBy, map, pipe, prop } from "remeda";
|
|
5
|
+
import { DiagnosticSeverity } from "vscode-languageserver-types";
|
|
6
|
+
import { logger as mainLogger } from "./logger.js";
|
|
7
|
+
import { ProjectsManager } from "./workspace/index.js";
|
|
8
|
+
const logger = mainLogger.getChild("LikeC4LanguageServices");
|
|
9
|
+
export class DefaultLikeC4LanguageServices {
|
|
10
|
+
constructor(services) {
|
|
11
|
+
this.services = services;
|
|
12
|
+
this.views = services.likec4.Views;
|
|
13
|
+
this.builder = services.likec4.ModelBuilder;
|
|
14
|
+
this.projectsManager = services.shared.workspace.ProjectsManager;
|
|
15
|
+
}
|
|
16
|
+
views;
|
|
17
|
+
builder;
|
|
18
|
+
projectsManager;
|
|
19
|
+
get workspaceUri() {
|
|
20
|
+
return this.services.shared.workspace.WorkspaceManager.workspaceUri;
|
|
21
|
+
}
|
|
22
|
+
projects() {
|
|
23
|
+
const projectsManager = this.services.shared.workspace.ProjectsManager;
|
|
24
|
+
const projectsWithDocs = pipe(
|
|
25
|
+
this.services.shared.workspace.LangiumDocuments.groupedByProject(),
|
|
26
|
+
entries(),
|
|
27
|
+
map(([projectId, docs]) => {
|
|
28
|
+
const id = projectId;
|
|
29
|
+
const { folder, config } = projectsManager.getProject(id);
|
|
30
|
+
return {
|
|
31
|
+
id,
|
|
32
|
+
folder,
|
|
33
|
+
config,
|
|
34
|
+
documents: map(docs, prop("uri"))
|
|
35
|
+
};
|
|
36
|
+
})
|
|
37
|
+
);
|
|
38
|
+
if (hasAtLeast(projectsWithDocs, 1)) {
|
|
39
|
+
return projectsWithDocs;
|
|
40
|
+
}
|
|
41
|
+
return [{
|
|
42
|
+
id: ProjectsManager.DefaultProjectId,
|
|
43
|
+
folder: this.services.shared.workspace.WorkspaceManager.workspaceUri,
|
|
44
|
+
config: {
|
|
45
|
+
name: "default"
|
|
46
|
+
},
|
|
47
|
+
documents: null
|
|
48
|
+
}];
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* Diagram is a computed view, layouted using Graphviz
|
|
52
|
+
* Used in React components
|
|
53
|
+
*/
|
|
54
|
+
async diagrams() {
|
|
55
|
+
return await this.views.diagrams();
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* Builds LikeC4Model from all documents
|
|
59
|
+
* Only computes view predicates {@link ComputedView} - i.e. no layout
|
|
60
|
+
* Not ready for rendering, but enough to traverse
|
|
61
|
+
*/
|
|
62
|
+
async computedModel(project) {
|
|
63
|
+
const projectId = this.projectsManager.ensureProjectId(project);
|
|
64
|
+
return await this.builder.buildLikeC4Model(projectId);
|
|
65
|
+
}
|
|
66
|
+
/**
|
|
67
|
+
* Same as {@link computedModel()}, but also applies layout
|
|
68
|
+
* Ready for rendering
|
|
69
|
+
*/
|
|
70
|
+
async layoutedModel(project) {
|
|
71
|
+
const projectId = this.projectsManager.ensureProjectId(project);
|
|
72
|
+
const parsed = await this.builder.parseModel(projectId);
|
|
73
|
+
if (!parsed) {
|
|
74
|
+
throw new Error("Failed to parse model");
|
|
75
|
+
}
|
|
76
|
+
const diagrams = await this.views.diagrams(projectId);
|
|
77
|
+
return LikeC4Model.create({
|
|
78
|
+
...parsed,
|
|
79
|
+
__: "layouted",
|
|
80
|
+
views: indexBy(diagrams, prop("id"))
|
|
81
|
+
});
|
|
82
|
+
}
|
|
83
|
+
getErrors() {
|
|
84
|
+
const docs = this.services.shared.workspace.LangiumDocuments.allExcludingBuiltin.toArray();
|
|
85
|
+
return docs.flatMap((doc) => {
|
|
86
|
+
return (doc.diagnostics ?? []).filter((d) => d.severity === DiagnosticSeverity.Error).map(({ message, range }) => ({
|
|
87
|
+
message,
|
|
88
|
+
line: range.start.line,
|
|
89
|
+
range,
|
|
90
|
+
sourceFsPath: doc.uri.fsPath
|
|
91
|
+
}));
|
|
92
|
+
});
|
|
93
|
+
}
|
|
94
|
+
/**
|
|
95
|
+
* TODO Replace with watcher
|
|
96
|
+
*/
|
|
97
|
+
async notifyUpdate({ changed, removed }) {
|
|
98
|
+
if (!changed && !removed) {
|
|
99
|
+
return false;
|
|
100
|
+
}
|
|
101
|
+
const mutex = this.services.shared.workspace.WorkspaceLock;
|
|
102
|
+
try {
|
|
103
|
+
let completed = false;
|
|
104
|
+
await mutex.write(async (token) => {
|
|
105
|
+
await this.services.shared.workspace.DocumentBuilder.update(
|
|
106
|
+
changed ? [URI.file(changed)] : [],
|
|
107
|
+
removed ? [URI.file(removed)] : [],
|
|
108
|
+
token
|
|
109
|
+
);
|
|
110
|
+
completed = !token.isCancellationRequested;
|
|
111
|
+
});
|
|
112
|
+
return completed;
|
|
113
|
+
} catch (e) {
|
|
114
|
+
logger.error(loggable(e));
|
|
115
|
+
return false;
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
}
|
package/dist/Rpc.js
CHANGED
|
@@ -1,19 +1,23 @@
|
|
|
1
|
-
import { filter, funnel, indexBy, map, pipe } from "remeda";
|
|
1
|
+
import { filter, flatMap, funnel, indexBy, keys, map, mapValues, pipe, sort } from "remeda";
|
|
2
2
|
import { logger as rootLogger } from "./logger.js";
|
|
3
|
-
import {
|
|
3
|
+
import {
|
|
4
|
+
LikeC4Model,
|
|
5
|
+
nonexhaustive
|
|
6
|
+
} from "@likec4/core";
|
|
4
7
|
import { Disposable, interruptAndCheck, URI, UriUtils } from "langium";
|
|
5
8
|
import { DiagnosticSeverity } from "vscode-languageserver";
|
|
6
|
-
import { isLikeC4LangiumDocument } from "./ast.js";
|
|
7
|
-
import { isLikeC4Builtin } from "./likec4lib.js";
|
|
8
9
|
import {
|
|
9
10
|
BuildDocuments,
|
|
10
11
|
ChangeView,
|
|
11
12
|
ComputeView,
|
|
13
|
+
DidChangeModelNotification,
|
|
12
14
|
FetchComputedModel,
|
|
13
15
|
FetchLayoutedModel,
|
|
16
|
+
FetchProjects,
|
|
17
|
+
FetchTelemetryMetrics,
|
|
18
|
+
FetchViewsFromAllProjects,
|
|
14
19
|
LayoutView,
|
|
15
20
|
Locate,
|
|
16
|
-
onDidChangeModel,
|
|
17
21
|
ValidateLayout
|
|
18
22
|
} from "./protocol.js";
|
|
19
23
|
import { ADisposable } from "./utils/index.js";
|
|
@@ -29,6 +33,7 @@ export class Rpc extends ADisposable {
|
|
|
29
33
|
const modelEditor = this.services.likec4.ModelChanges;
|
|
30
34
|
const views = this.services.likec4.Views;
|
|
31
35
|
const connection = this.services.shared.lsp.Connection;
|
|
36
|
+
const projects = this.services.shared.workspace.ProjectsManager;
|
|
32
37
|
if (!connection) {
|
|
33
38
|
logger.info(`[ServerRpc] no connection, not initializing`);
|
|
34
39
|
return;
|
|
@@ -39,14 +44,14 @@ export class Rpc extends ADisposable {
|
|
|
39
44
|
const notifyModelParsed = funnel(
|
|
40
45
|
() => {
|
|
41
46
|
logger.debug`sendNotification ${"onDidChangeModel"}`;
|
|
42
|
-
connection.sendNotification(
|
|
47
|
+
connection.sendNotification(DidChangeModelNotification.type, "").catch((e) => {
|
|
43
48
|
logger.warn(`[ServerRpc] error sending onDidChangeModel: ${e}`);
|
|
44
49
|
return Promise.resolve();
|
|
45
50
|
});
|
|
46
51
|
},
|
|
47
52
|
{
|
|
48
53
|
triggerAt: "end",
|
|
49
|
-
minQuietPeriodMs:
|
|
54
|
+
minQuietPeriodMs: 100,
|
|
50
55
|
maxBurstDurationMs: 500,
|
|
51
56
|
minGapMs: 300
|
|
52
57
|
}
|
|
@@ -54,28 +59,29 @@ export class Rpc extends ADisposable {
|
|
|
54
59
|
let isFirstBuild = true;
|
|
55
60
|
this.onDispose(
|
|
56
61
|
modelBuilder.onModelParsed(() => notifyModelParsed.call()),
|
|
57
|
-
connection.onRequest(FetchComputedModel.
|
|
58
|
-
logger.debug`received request ${"fetchComputedModel"}`;
|
|
62
|
+
connection.onRequest(FetchComputedModel.req, async ({ projectId, cleanCaches }, cancelToken) => {
|
|
63
|
+
logger.debug`received request ${"fetchComputedModel"} for project ${projectId}`;
|
|
59
64
|
if (cleanCaches) {
|
|
60
|
-
const
|
|
61
|
-
|
|
65
|
+
const docs = projectId ? LangiumDocuments.projectDocuments(projectId) : LangiumDocuments.all;
|
|
66
|
+
const uris = docs.map((d) => d.uri).toArray();
|
|
67
|
+
await DocumentBuilder.update(uris, [], cancelToken);
|
|
62
68
|
}
|
|
63
|
-
const likec4model = await modelBuilder.buildLikeC4Model(cancelToken);
|
|
69
|
+
const likec4model = await modelBuilder.buildLikeC4Model(projectId, cancelToken);
|
|
64
70
|
if (likec4model !== LikeC4Model.EMPTY) {
|
|
65
71
|
return { model: likec4model.$model };
|
|
66
72
|
}
|
|
67
73
|
return { model: null };
|
|
68
74
|
}),
|
|
69
|
-
connection.onRequest(ComputeView.
|
|
70
|
-
const view = await modelBuilder.computeView(viewId, cancelToken);
|
|
75
|
+
connection.onRequest(ComputeView.req, async ({ viewId, projectId }, cancelToken) => {
|
|
76
|
+
const view = await modelBuilder.computeView(viewId, projectId, cancelToken);
|
|
71
77
|
return { view };
|
|
72
78
|
}),
|
|
73
|
-
connection.onRequest(FetchLayoutedModel.
|
|
74
|
-
const model = await modelBuilder.parseModel(cancelToken);
|
|
79
|
+
connection.onRequest(FetchLayoutedModel.req, async ({ projectId }, cancelToken) => {
|
|
80
|
+
const model = await modelBuilder.parseModel(projectId, cancelToken);
|
|
75
81
|
if (model === null) {
|
|
76
82
|
return { model: null };
|
|
77
83
|
}
|
|
78
|
-
const diagrams = await views.diagrams();
|
|
84
|
+
const diagrams = await views.diagrams(projectId, cancelToken);
|
|
79
85
|
return {
|
|
80
86
|
model: {
|
|
81
87
|
...model,
|
|
@@ -84,20 +90,59 @@ export class Rpc extends ADisposable {
|
|
|
84
90
|
}
|
|
85
91
|
};
|
|
86
92
|
}),
|
|
87
|
-
connection.onRequest(LayoutView.
|
|
88
|
-
logger.debug`received request ${"layoutView"} of ${viewId}`;
|
|
89
|
-
const result = await views.layoutView(viewId, cancelToken);
|
|
93
|
+
connection.onRequest(LayoutView.req, async ({ viewId, projectId }, cancelToken) => {
|
|
94
|
+
logger.debug`received request ${"layoutView"} of ${viewId} from project ${projectId}`;
|
|
95
|
+
const result = await views.layoutView(viewId, projectId, cancelToken);
|
|
90
96
|
return { result };
|
|
91
97
|
}),
|
|
92
|
-
connection.onRequest(ValidateLayout.Req, async (cancelToken) => {
|
|
93
|
-
const layouts = await views.layoutAllViews(cancelToken);
|
|
98
|
+
connection.onRequest(ValidateLayout.Req, async ({ projectId }, cancelToken) => {
|
|
99
|
+
const layouts = await views.layoutAllViews(projectId, cancelToken);
|
|
94
100
|
const result = reportLayoutDrift(layouts.map((l) => l.diagram));
|
|
95
101
|
return { result };
|
|
96
102
|
}),
|
|
103
|
+
connection.onRequest(FetchProjects.req, async (_cancelToken) => {
|
|
104
|
+
logger.debug`received request ${"FetchProjects"}`;
|
|
105
|
+
const docsByProject = LangiumDocuments.groupedByProject();
|
|
106
|
+
return {
|
|
107
|
+
projects: mapValues(docsByProject, (docs) => map(docs, (d) => d.uri.toString()))
|
|
108
|
+
};
|
|
109
|
+
}),
|
|
110
|
+
connection.onRequest(FetchViewsFromAllProjects.req, async (cancelToken) => {
|
|
111
|
+
logger.debug`received request ${"FetchViewsFromAllProjects"}`;
|
|
112
|
+
const promises = projects.all.map(async (projectId) => {
|
|
113
|
+
const computedViews = await views.computedViews(projectId, cancelToken);
|
|
114
|
+
return pipe(
|
|
115
|
+
computedViews,
|
|
116
|
+
map((v) => ({
|
|
117
|
+
id: v.id,
|
|
118
|
+
title: v.title ?? v.id,
|
|
119
|
+
projectId
|
|
120
|
+
})),
|
|
121
|
+
sort((a, b) => {
|
|
122
|
+
if (a.id === "index") {
|
|
123
|
+
return -1;
|
|
124
|
+
}
|
|
125
|
+
if (b.id === "index") {
|
|
126
|
+
return 1;
|
|
127
|
+
}
|
|
128
|
+
return a.title.localeCompare(b.title);
|
|
129
|
+
})
|
|
130
|
+
);
|
|
131
|
+
});
|
|
132
|
+
const results = await Promise.allSettled(promises);
|
|
133
|
+
await interruptAndCheck(cancelToken);
|
|
134
|
+
return {
|
|
135
|
+
views: pipe(
|
|
136
|
+
results,
|
|
137
|
+
filter((r) => r.status === "fulfilled"),
|
|
138
|
+
flatMap((r) => r.value)
|
|
139
|
+
)
|
|
140
|
+
};
|
|
141
|
+
}),
|
|
97
142
|
connection.onRequest(BuildDocuments.Req, async ({ docs }, cancelToken) => {
|
|
98
143
|
const changed = docs.map((d) => URI.parse(d));
|
|
99
144
|
const notChanged = (uri) => changed.every((c) => !UriUtils.equals(c, uri));
|
|
100
|
-
const deleted = LangiumDocuments.
|
|
145
|
+
const deleted = LangiumDocuments.allExcludingBuiltin.toArray().filter((d) => notChanged(d.uri)).map((d) => d.uri);
|
|
101
146
|
logger.debug(
|
|
102
147
|
`[ServerRpc] received request to build:
|
|
103
148
|
changed (total ${changed.length}):${docs.map((d) => "\n - " + d).join("")}
|
|
@@ -126,21 +171,54 @@ export class Rpc extends ADisposable {
|
|
|
126
171
|
connection.onRequest(Locate.Req, (params) => {
|
|
127
172
|
switch (true) {
|
|
128
173
|
case "element" in params:
|
|
129
|
-
return modelLocator.locateElement(params.element, params.
|
|
174
|
+
return modelLocator.locateElement(params.element, params.projectId);
|
|
130
175
|
case "relation" in params:
|
|
131
|
-
return modelLocator.locateRelation(params.relation);
|
|
176
|
+
return modelLocator.locateRelation(params.relation, params.projectId);
|
|
132
177
|
case "view" in params:
|
|
133
|
-
return modelLocator.locateView(params.view);
|
|
178
|
+
return modelLocator.locateView(params.view, params.projectId);
|
|
134
179
|
case "deployment" in params:
|
|
135
|
-
return modelLocator.locateDeploymentElement(params.deployment, params.
|
|
180
|
+
return modelLocator.locateDeploymentElement(params.deployment, params.projectId);
|
|
136
181
|
default:
|
|
137
182
|
nonexhaustive(params);
|
|
138
183
|
}
|
|
139
184
|
}),
|
|
140
185
|
connection.onRequest(ChangeView.Req, async (request, _cancelToken) => {
|
|
141
|
-
logger.debug`received request ${"changeView"} of ${request.viewId}`;
|
|
186
|
+
logger.debug`received request ${"changeView"} of ${request.viewId} from project ${request.projectId}`;
|
|
142
187
|
return await modelEditor.applyChange(request);
|
|
143
188
|
}),
|
|
189
|
+
connection.onRequest(FetchTelemetryMetrics.req, async (cancelToken) => {
|
|
190
|
+
const projectsIds = [...projects.all];
|
|
191
|
+
const promises = projectsIds.map(async (projectId) => {
|
|
192
|
+
const model = await modelBuilder.buildLikeC4Model(projectId, cancelToken);
|
|
193
|
+
if (model === LikeC4Model.EMPTY) {
|
|
194
|
+
return Promise.reject(new Error(`Model is empty`));
|
|
195
|
+
}
|
|
196
|
+
return {
|
|
197
|
+
elementKinds: keys(model.$model.specification.elements).length,
|
|
198
|
+
relationshipKinds: keys(model.$model.specification.relationships).length,
|
|
199
|
+
tags: model.$model.specification.tags.length,
|
|
200
|
+
elements: keys(model.$model.elements).length,
|
|
201
|
+
relationships: keys(model.$model.relations).length,
|
|
202
|
+
views: keys(model.$model.views).length,
|
|
203
|
+
projects: 1
|
|
204
|
+
};
|
|
205
|
+
});
|
|
206
|
+
const results = await Promise.allSettled(promises);
|
|
207
|
+
await interruptAndCheck(cancelToken);
|
|
208
|
+
const values = results.filter((r) => r.status === "fulfilled").map((r) => r.value);
|
|
209
|
+
const metrics = values.length > 0 ? values.reduce((acc, r) => ({
|
|
210
|
+
elementKinds: acc.elementKinds + r.elementKinds,
|
|
211
|
+
relationshipKinds: acc.relationshipKinds + r.relationshipKinds,
|
|
212
|
+
tags: acc.tags + r.tags,
|
|
213
|
+
elements: acc.elements + r.elements,
|
|
214
|
+
relationships: acc.relationships + r.relationships,
|
|
215
|
+
views: acc.views + r.views,
|
|
216
|
+
projects: acc.projects + 1
|
|
217
|
+
})) : null;
|
|
218
|
+
return {
|
|
219
|
+
metrics
|
|
220
|
+
};
|
|
221
|
+
}),
|
|
144
222
|
Disposable.create(() => {
|
|
145
223
|
notifyModelParsed.cancel();
|
|
146
224
|
})
|
package/dist/ast.d.ts
CHANGED
|
@@ -7,6 +7,14 @@ import * as ast from './generated/ast';
|
|
|
7
7
|
import type { IsValidFn } from './validation';
|
|
8
8
|
export { ast };
|
|
9
9
|
declare const idattr: unique symbol;
|
|
10
|
+
declare module 'langium' {
|
|
11
|
+
interface LangiumDocument {
|
|
12
|
+
likec4ProjectId?: c4.ProjectId;
|
|
13
|
+
}
|
|
14
|
+
interface AstNodeDescription {
|
|
15
|
+
likec4ProjectId?: c4.ProjectId;
|
|
16
|
+
}
|
|
17
|
+
}
|
|
10
18
|
declare module './generated/ast' {
|
|
11
19
|
interface Element {
|
|
12
20
|
[idattr]?: c4.Fqn | undefined;
|
|
@@ -173,8 +181,10 @@ export interface LikeC4DocumentProps {
|
|
|
173
181
|
}
|
|
174
182
|
type LikeC4GrammarDocument = Omit<LangiumDocument<LikeC4Grammar>, 'diagnostics'>;
|
|
175
183
|
export interface LikeC4LangiumDocument extends LikeC4GrammarDocument, LikeC4DocumentProps {
|
|
184
|
+
likec4ProjectId: c4.ProjectId;
|
|
176
185
|
}
|
|
177
186
|
export interface ParsedLikeC4LangiumDocument extends LikeC4GrammarDocument, Required<LikeC4DocumentProps> {
|
|
187
|
+
likec4ProjectId: c4.ProjectId;
|
|
178
188
|
}
|
|
179
189
|
export declare function isLikeC4LangiumDocument(doc: LangiumDocument): doc is LikeC4LangiumDocument;
|
|
180
190
|
export declare function isParsedLikeC4LangiumDocument(doc: LangiumDocument): doc is ParsedLikeC4LangiumDocument;
|