@likec4/language-server 1.38.1 → 1.39.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/dist/LikeC4LanguageServices.d.ts +7 -0
- package/dist/LikeC4LanguageServices.js +25 -4
- package/dist/Rpc.js +9 -2
- package/dist/ast.d.ts +1 -1
- package/dist/ast.js +2 -1
- package/dist/bundled.d.ts +8 -0
- package/dist/bundled.js +40 -0
- package/dist/bundled.mjs +3629 -3523
- package/dist/filesystem/ChokidarWatcher.js +12 -9
- package/dist/filesystem/LikeC4FileSystem.d.ts +0 -2
- package/dist/filesystem/LikeC4FileSystem.js +7 -5
- package/dist/filesystem/index.d.ts +7 -0
- package/dist/filesystem/index.js +3 -0
- package/dist/generated/ast.d.ts +1 -0
- package/dist/generated/ast.js +2 -1
- package/dist/generated/grammar.js +1 -1
- package/dist/generated-lib/icons.js +1 -1
- package/dist/index.d.ts +1 -0
- package/dist/logger.js +1 -1
- package/dist/mcp/MCPServerFactory.js +6 -5
- package/dist/mcp/server/StreamableLikeC4MCPServer.d.ts +2 -2
- package/dist/mcp/server/StreamableLikeC4MCPServer.js +97 -100
- package/dist/mcp/server/WithMCPServer.d.ts +3 -1
- package/dist/mcp/server/WithMCPServer.js +6 -5
- package/dist/mcp/tools/search-element.js +26 -11
- package/dist/mcp/utils.js +2 -2
- package/dist/model/builder/MergedSpecification.d.ts +2 -2
- package/dist/model/builder/MergedSpecification.js +4 -7
- package/dist/model/builder/assignTagColors.js +1 -1
- package/dist/model/builder/buildModel.d.ts +3 -8
- package/dist/model/builder/buildModel.js +14 -11
- package/dist/model/model-builder.d.ts +1 -1
- package/dist/model/model-locator.js +2 -1
- package/dist/model/model-parser.d.ts +19 -46
- package/dist/model/model-parser.js +13 -3
- package/dist/model/parser/Base.d.ts +4 -7
- package/dist/model/parser/Base.js +19 -0
- package/dist/model/parser/DeploymentModelParser.d.ts +2 -5
- package/dist/model/parser/DeploymentViewParser.d.ts +2 -5
- package/dist/model/parser/FqnRefParser.d.ts +2 -5
- package/dist/model/parser/GlobalsParser.d.ts +2 -5
- package/dist/model/parser/ImportsParser.d.ts +2 -5
- package/dist/model/parser/ModelParser.d.ts +2 -5
- package/dist/model/parser/PredicatesParser.d.ts +2 -5
- package/dist/model/parser/SpecificationParser.d.ts +2 -5
- package/dist/model/parser/ViewsParser.d.ts +2 -5
- package/dist/protocol.d.ts +16 -2
- package/dist/protocol.js +4 -0
- package/dist/test/testServices.d.ts +5 -1
- package/dist/test/testServices.js +18 -3
- package/dist/utils/disposable.d.ts +1 -1
- package/dist/utils/stringHash.js +1 -1
- package/dist/view-utils/resolve-relative-paths.js +1 -1
- package/dist/workspace/ProjectsManager.d.ts +24 -10
- package/dist/workspace/ProjectsManager.js +72 -27
- package/dist/workspace/WorkspaceManager.js +5 -4
- package/package.json +20 -26
- package/dist/config/index.d.ts +0 -1
- package/dist/config/index.js +0 -1
- package/dist/config/schema.d.ts +0 -10
- package/dist/config/schema.js +0 -39
|
@@ -28,11 +28,7 @@ export declare function DeploymentViewParser<TBase extends WithExpressionV2 & Wi
|
|
|
28
28
|
isValid: import("../../validation").IsValidFn;
|
|
29
29
|
readonly services: import("../..").LikeC4Services;
|
|
30
30
|
readonly doc: import("../../ast").ParsedLikeC4LangiumDocument;
|
|
31
|
-
get project():
|
|
32
|
-
id: c4.ProjectId;
|
|
33
|
-
folderUri: c4;
|
|
34
|
-
config: Readonly<import("../../config").ProjectConfig>;
|
|
35
|
-
};
|
|
31
|
+
get project(): import("../../workspace").Project;
|
|
36
32
|
resolveFqn(node: ast.FqnReferenceable): c4.Fqn;
|
|
37
33
|
getAstNodePath(node: c4): any;
|
|
38
34
|
getMetadata(metadataAstNode: ast.MetadataProperty | undefined): {
|
|
@@ -48,6 +44,7 @@ export declare function DeploymentViewParser<TBase extends WithExpressionV2 & Wi
|
|
|
48
44
|
convertLinks(source?: ast.LinkProperty["$container"]): c4.Link[] | undefined;
|
|
49
45
|
parseLinks(source?: ast.LinkProperty["$container"]): c4.Link[] | undefined;
|
|
50
46
|
parseIconProperty(prop: ast.IconProperty | undefined): c4.IconUrl | undefined;
|
|
47
|
+
parseImageAlias(value: string): string | undefined;
|
|
51
48
|
parseColorLiteral(astNode: ast.ColorLiteral): c4.ColorLiteral | undefined;
|
|
52
49
|
parseElementStyle(elementProps: Array<ast.ElementProperty> | ast.ElementStyleProperty | undefined): import("../../ast").ParsedElementStyle;
|
|
53
50
|
parseStyleProps(styleProps: Array<ast.StyleProperty> | undefined): import("../../ast").ParsedElementStyle;
|
|
@@ -23,11 +23,7 @@ export declare function ExpressionV2Parser<TBase extends Base>(B: TBase): {
|
|
|
23
23
|
isValid: import("../../validation").IsValidFn;
|
|
24
24
|
readonly services: import("../..").LikeC4Services;
|
|
25
25
|
readonly doc: import("../../ast").ParsedLikeC4LangiumDocument;
|
|
26
|
-
get project():
|
|
27
|
-
id: c4.ProjectId;
|
|
28
|
-
folderUri: c4;
|
|
29
|
-
config: Readonly<import("../../config").ProjectConfig>;
|
|
30
|
-
};
|
|
26
|
+
get project(): import("../../workspace").Project;
|
|
31
27
|
resolveFqn(node: ast.FqnReferenceable): c4.Fqn;
|
|
32
28
|
getAstNodePath(node: c4): any;
|
|
33
29
|
getMetadata(metadataAstNode: ast.MetadataProperty | undefined): {
|
|
@@ -43,6 +39,7 @@ export declare function ExpressionV2Parser<TBase extends Base>(B: TBase): {
|
|
|
43
39
|
convertLinks(source?: ast.LinkProperty["$container"]): c4.Link[] | undefined;
|
|
44
40
|
parseLinks(source?: ast.LinkProperty["$container"]): c4.Link[] | undefined;
|
|
45
41
|
parseIconProperty(prop: ast.IconProperty | undefined): c4.IconUrl | undefined;
|
|
42
|
+
parseImageAlias(value: string): string | undefined;
|
|
46
43
|
parseColorLiteral(astNode: ast.ColorLiteral): c4.ColorLiteral | undefined;
|
|
47
44
|
parseElementStyle(elementProps: Array<ast.ElementProperty> | ast.ElementStyleProperty | undefined): import("../../ast").ParsedElementStyle;
|
|
48
45
|
parseStyleProps(styleProps: Array<ast.StyleProperty> | undefined): import("../../ast").ParsedElementStyle;
|
|
@@ -52,11 +52,7 @@ export declare function GlobalsParser<TBase extends WithViewsParser>(B: TBase):
|
|
|
52
52
|
isValid: import("../../validation").IsValidFn;
|
|
53
53
|
readonly services: import("../..").LikeC4Services;
|
|
54
54
|
readonly doc: import("../../ast").ParsedLikeC4LangiumDocument;
|
|
55
|
-
get project():
|
|
56
|
-
id: c4.ProjectId;
|
|
57
|
-
folderUri: c4;
|
|
58
|
-
config: Readonly<import("../../config").ProjectConfig>;
|
|
59
|
-
};
|
|
55
|
+
get project(): import("../../workspace").Project;
|
|
60
56
|
resolveFqn(node: ast.FqnReferenceable): c4.Fqn;
|
|
61
57
|
getAstNodePath(node: c4): any;
|
|
62
58
|
getMetadata(metadataAstNode: ast.MetadataProperty | undefined): {
|
|
@@ -72,6 +68,7 @@ export declare function GlobalsParser<TBase extends WithViewsParser>(B: TBase):
|
|
|
72
68
|
convertLinks(source?: ast.LinkProperty["$container"]): c4.Link[] | undefined;
|
|
73
69
|
parseLinks(source?: ast.LinkProperty["$container"]): c4.Link[] | undefined;
|
|
74
70
|
parseIconProperty(prop: ast.IconProperty | undefined): c4.IconUrl | undefined;
|
|
71
|
+
parseImageAlias(value: string): string | undefined;
|
|
75
72
|
parseColorLiteral(astNode: ast.ColorLiteral): c4.ColorLiteral | undefined;
|
|
76
73
|
parseElementStyle(elementProps: Array<ast.ElementProperty> | ast.ElementStyleProperty | undefined): import("../../ast").ParsedElementStyle;
|
|
77
74
|
parseStyleProps(styleProps: Array<ast.StyleProperty> | undefined): import("../../ast").ParsedElementStyle;
|
|
@@ -7,11 +7,7 @@ export declare function ImportsParser<TBase extends Base>(B: TBase): {
|
|
|
7
7
|
isValid: import("../../validation").IsValidFn;
|
|
8
8
|
readonly services: import("../..").LikeC4Services;
|
|
9
9
|
readonly doc: import("../../ast").ParsedLikeC4LangiumDocument;
|
|
10
|
-
get project():
|
|
11
|
-
id: ProjectId;
|
|
12
|
-
folderUri: ProjectId;
|
|
13
|
-
config: Readonly<import("../../config").ProjectConfig>;
|
|
14
|
-
};
|
|
10
|
+
get project(): import("../../workspace").Project;
|
|
15
11
|
resolveFqn(node: ast.FqnReferenceable): ProjectId;
|
|
16
12
|
getAstNodePath(node: ProjectId): any;
|
|
17
13
|
getMetadata(metadataAstNode: ast.MetadataProperty | undefined): {
|
|
@@ -27,6 +23,7 @@ export declare function ImportsParser<TBase extends Base>(B: TBase): {
|
|
|
27
23
|
convertLinks(source?: ast.LinkProperty["$container"]): ProjectId[] | undefined;
|
|
28
24
|
parseLinks(source?: ast.LinkProperty["$container"]): ProjectId[] | undefined;
|
|
29
25
|
parseIconProperty(prop: ast.IconProperty | undefined): ProjectId | undefined;
|
|
26
|
+
parseImageAlias(value: string): string | undefined;
|
|
30
27
|
parseColorLiteral(astNode: ast.ColorLiteral): ProjectId | undefined;
|
|
31
28
|
parseElementStyle(elementProps: Array<ast.ElementProperty> | ast.ElementStyleProperty | undefined): import("../../ast").ParsedElementStyle;
|
|
32
29
|
parseStyleProps(styleProps: Array<ast.StyleProperty> | undefined): import("../../ast").ParsedElementStyle;
|
|
@@ -29,11 +29,7 @@ export declare function ModelParser<TBase extends WithExpressionV2>(B: TBase): {
|
|
|
29
29
|
isValid: import("../../validation").IsValidFn;
|
|
30
30
|
readonly services: import("../..").LikeC4Services;
|
|
31
31
|
readonly doc: import("../../ast").ParsedLikeC4LangiumDocument;
|
|
32
|
-
get project():
|
|
33
|
-
id: c4.ProjectId;
|
|
34
|
-
folderUri: c4;
|
|
35
|
-
config: Readonly<import("../../config").ProjectConfig>;
|
|
36
|
-
};
|
|
32
|
+
get project(): import("../../workspace").Project;
|
|
37
33
|
resolveFqn(node: ast.FqnReferenceable): c4.Fqn;
|
|
38
34
|
getAstNodePath(node: c4): any;
|
|
39
35
|
getMetadata(metadataAstNode: ast.MetadataProperty | undefined): {
|
|
@@ -49,6 +45,7 @@ export declare function ModelParser<TBase extends WithExpressionV2>(B: TBase): {
|
|
|
49
45
|
convertLinks(source?: ast.LinkProperty["$container"]): c4.Link[] | undefined;
|
|
50
46
|
parseLinks(source?: ast.LinkProperty["$container"]): c4.Link[] | undefined;
|
|
51
47
|
parseIconProperty(prop: ast.IconProperty | undefined): c4.IconUrl | undefined;
|
|
48
|
+
parseImageAlias(value: string): string | undefined;
|
|
52
49
|
parseColorLiteral(astNode: ast.ColorLiteral): c4.ColorLiteral | undefined;
|
|
53
50
|
parseElementStyle(elementProps: Array<ast.ElementProperty> | ast.ElementStyleProperty | undefined): import("../../ast").ParsedElementStyle;
|
|
54
51
|
parseStyleProps(styleProps: Array<ast.StyleProperty> | undefined): import("../../ast").ParsedElementStyle;
|
|
@@ -34,11 +34,7 @@ export declare function PredicatesParser<TBase extends WithExpressionV2>(B: TBas
|
|
|
34
34
|
isValid: import("../../validation").IsValidFn;
|
|
35
35
|
readonly services: import("../..").LikeC4Services;
|
|
36
36
|
readonly doc: import("../../ast").ParsedLikeC4LangiumDocument;
|
|
37
|
-
get project():
|
|
38
|
-
id: c4.ProjectId;
|
|
39
|
-
folderUri: c4;
|
|
40
|
-
config: Readonly<import("../../config").ProjectConfig>;
|
|
41
|
-
};
|
|
37
|
+
get project(): import("../../workspace").Project;
|
|
42
38
|
resolveFqn(node: ast.FqnReferenceable): c4.Fqn;
|
|
43
39
|
getAstNodePath(node: c4): any;
|
|
44
40
|
getMetadata(metadataAstNode: ast.MetadataProperty | undefined): {
|
|
@@ -54,6 +50,7 @@ export declare function PredicatesParser<TBase extends WithExpressionV2>(B: TBas
|
|
|
54
50
|
convertLinks(source?: ast.LinkProperty["$container"]): c4.Link[] | undefined;
|
|
55
51
|
parseLinks(source?: ast.LinkProperty["$container"]): c4.Link[] | undefined;
|
|
56
52
|
parseIconProperty(prop: ast.IconProperty | undefined): c4.IconUrl | undefined;
|
|
53
|
+
parseImageAlias(value: string): string | undefined;
|
|
57
54
|
parseColorLiteral(astNode: ast.ColorLiteral): c4.ColorLiteral | undefined;
|
|
58
55
|
parseElementStyle(elementProps: Array<ast.ElementProperty> | ast.ElementStyleProperty | undefined): import("../../ast").ParsedElementStyle;
|
|
59
56
|
parseStyleProps(styleProps: Array<ast.StyleProperty> | undefined): import("../../ast").ParsedElementStyle;
|
|
@@ -13,11 +13,7 @@ export declare function SpecificationParser<TBase extends Base>(B: TBase): {
|
|
|
13
13
|
isValid: import("../../validation").IsValidFn;
|
|
14
14
|
readonly services: import("../..").LikeC4Services;
|
|
15
15
|
readonly doc: import("../../ast").ParsedLikeC4LangiumDocument;
|
|
16
|
-
get project():
|
|
17
|
-
id: c4.ProjectId;
|
|
18
|
-
folderUri: c4;
|
|
19
|
-
config: Readonly<import("../../config").ProjectConfig>;
|
|
20
|
-
};
|
|
16
|
+
get project(): import("../../workspace").Project;
|
|
21
17
|
resolveFqn(node: ast.FqnReferenceable): c4.Fqn;
|
|
22
18
|
getAstNodePath(node: c4): any;
|
|
23
19
|
getMetadata(metadataAstNode: ast.MetadataProperty | undefined): {
|
|
@@ -33,6 +29,7 @@ export declare function SpecificationParser<TBase extends Base>(B: TBase): {
|
|
|
33
29
|
convertLinks(source?: ast.LinkProperty["$container"]): c4.Link[] | undefined;
|
|
34
30
|
parseLinks(source?: ast.LinkProperty["$container"]): c4.Link[] | undefined;
|
|
35
31
|
parseIconProperty(prop: ast.IconProperty | undefined): c4.IconUrl | undefined;
|
|
32
|
+
parseImageAlias(value: string): string | undefined;
|
|
36
33
|
parseColorLiteral(astNode: ast.ColorLiteral): c4.ColorLiteral | undefined;
|
|
37
34
|
parseElementStyle(elementProps: Array<ast.ElementProperty> | ast.ElementStyleProperty | undefined): import("../../ast").ParsedElementStyle;
|
|
38
35
|
parseStyleProps(styleProps: Array<ast.StyleProperty> | undefined): import("../../ast").ParsedElementStyle;
|
|
@@ -50,11 +50,7 @@ export declare function ViewsParser<TBase extends WithPredicates & WithDeploymen
|
|
|
50
50
|
isValid: import("../../validation").IsValidFn;
|
|
51
51
|
readonly services: import("../..").LikeC4Services;
|
|
52
52
|
readonly doc: import("../../ast").ParsedLikeC4LangiumDocument;
|
|
53
|
-
get project():
|
|
54
|
-
id: c4.ProjectId;
|
|
55
|
-
folderUri: c4;
|
|
56
|
-
config: Readonly<import("../../config").ProjectConfig>;
|
|
57
|
-
};
|
|
53
|
+
get project(): import("../../workspace").Project;
|
|
58
54
|
resolveFqn(node: ast.FqnReferenceable): c4.Fqn;
|
|
59
55
|
getAstNodePath(node: c4): any;
|
|
60
56
|
getMetadata(metadataAstNode: ast.MetadataProperty | undefined): {
|
|
@@ -70,6 +66,7 @@ export declare function ViewsParser<TBase extends WithPredicates & WithDeploymen
|
|
|
70
66
|
convertLinks(source?: ast.LinkProperty["$container"]): c4.Link[] | undefined;
|
|
71
67
|
parseLinks(source?: ast.LinkProperty["$container"]): c4.Link[] | undefined;
|
|
72
68
|
parseIconProperty(prop: ast.IconProperty | undefined): c4.IconUrl | undefined;
|
|
69
|
+
parseImageAlias(value: string): string | undefined;
|
|
73
70
|
parseColorLiteral(astNode: ast.ColorLiteral): c4.ColorLiteral | undefined;
|
|
74
71
|
parseElementStyle(elementProps: Array<ast.ElementProperty> | ast.ElementStyleProperty | undefined): import("../../ast").ParsedElementStyle;
|
|
75
72
|
parseStyleProps(styleProps: Array<ast.StyleProperty> | undefined): import("../../ast").ParsedElementStyle;
|
package/dist/protocol.d.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
|
+
import type { LikeC4ProjectJsonConfig } from '@likec4/config';
|
|
1
2
|
import type { ComputedLikeC4ModelData, ComputedView, DeploymentFqn, DiagramView, Fqn, LayoutedLikeC4ModelData, NonEmptyArray, ProjectId, RelationId, ViewChange, ViewId } from '@likec4/core';
|
|
2
3
|
import { NotificationType, RequestType, RequestType0 } from 'vscode-jsonrpc';
|
|
3
4
|
import type { DiagnosticSeverity, DocumentUri, Location, Position, Range, URI } from 'vscode-languageserver-types';
|
|
4
|
-
import type { ProjectConfig } from './config';
|
|
5
5
|
export declare namespace DidChangeModelNotification {
|
|
6
6
|
const type: NotificationType<string>;
|
|
7
7
|
type Type = typeof type;
|
|
@@ -139,7 +139,7 @@ export declare namespace FetchProjects {
|
|
|
139
139
|
projects: {
|
|
140
140
|
[projectId: ProjectId]: {
|
|
141
141
|
folder: URI;
|
|
142
|
-
config:
|
|
142
|
+
config: LikeC4ProjectJsonConfig;
|
|
143
143
|
docs: NonEmptyArray<DocumentUri>;
|
|
144
144
|
};
|
|
145
145
|
};
|
|
@@ -147,6 +147,20 @@ export declare namespace FetchProjects {
|
|
|
147
147
|
const req: RequestType0<Res, void>;
|
|
148
148
|
type Req = typeof req;
|
|
149
149
|
}
|
|
150
|
+
/**
|
|
151
|
+
* Request from the client to register a project.
|
|
152
|
+
*/
|
|
153
|
+
export declare namespace RegisterProject {
|
|
154
|
+
type Params = {
|
|
155
|
+
folderUri: URI;
|
|
156
|
+
config: LikeC4ProjectJsonConfig;
|
|
157
|
+
};
|
|
158
|
+
type Res = {
|
|
159
|
+
id: ProjectId;
|
|
160
|
+
};
|
|
161
|
+
const req: RequestType<Params, Res, void>;
|
|
162
|
+
type Req = typeof req;
|
|
163
|
+
}
|
|
150
164
|
/**
|
|
151
165
|
* Request to build documents.
|
|
152
166
|
*/
|
package/dist/protocol.js
CHANGED
|
@@ -39,6 +39,10 @@ export var FetchProjects;
|
|
|
39
39
|
((FetchProjects2) => {
|
|
40
40
|
FetchProjects2.req = new RequestType0("likec4/fetch-projects");
|
|
41
41
|
})(FetchProjects || (FetchProjects = {}));
|
|
42
|
+
export var RegisterProject;
|
|
43
|
+
((RegisterProject2) => {
|
|
44
|
+
RegisterProject2.req = new RequestType("likec4/register-project");
|
|
45
|
+
})(RegisterProject || (RegisterProject = {}));
|
|
42
46
|
export var BuildDocuments;
|
|
43
47
|
((BuildDocuments2) => {
|
|
44
48
|
BuildDocuments2.Req = new RequestType("likec4/build");
|
|
@@ -1,8 +1,12 @@
|
|
|
1
|
+
import type { LikeC4ProjectJsonConfig } from '@likec4/config';
|
|
1
2
|
import type { ComputedLikeC4ModelData } from '@likec4/core';
|
|
2
3
|
import type { LiteralUnion } from 'type-fest';
|
|
3
4
|
import { URI } from 'vscode-uri';
|
|
4
5
|
import type { LikeC4LangiumDocument } from '../ast';
|
|
5
|
-
export declare function createTestServices(
|
|
6
|
+
export declare function createTestServices(options?: {
|
|
7
|
+
workspace?: string;
|
|
8
|
+
projectConfig?: Partial<LikeC4ProjectJsonConfig>;
|
|
9
|
+
}): {
|
|
6
10
|
services: any;
|
|
7
11
|
addDocument: (input: string, uri?: string) => Promise<LikeC4LangiumDocument>;
|
|
8
12
|
parse: (input: string, uri?: string) => Promise<LikeC4LangiumDocument>;
|
|
@@ -6,7 +6,9 @@ import { DiagnosticSeverity } from "vscode-languageserver-types";
|
|
|
6
6
|
import { URI, Utils } from "vscode-uri";
|
|
7
7
|
import { NoopFileSystem } from "../filesystem/index.js";
|
|
8
8
|
import { createLanguageServices } from "../module.js";
|
|
9
|
-
export function createTestServices(
|
|
9
|
+
export function createTestServices(options) {
|
|
10
|
+
const workspace = options?.workspace ?? "file:///test/workspace";
|
|
11
|
+
const projectConfig = options?.projectConfig;
|
|
10
12
|
const services = createLanguageServices(NoopFileSystem).likec4;
|
|
11
13
|
const metaData = services.LanguageMetaData;
|
|
12
14
|
const langiumDocuments = services.shared.workspace.LangiumDocuments;
|
|
@@ -15,7 +17,7 @@ export function createTestServices(workspace = "file:///test/workspace") {
|
|
|
15
17
|
const workspaceUri = URI.parse(workspace);
|
|
16
18
|
const formatter = services.lsp.Formatter;
|
|
17
19
|
const workspaceFolder = {
|
|
18
|
-
name: "test",
|
|
20
|
+
name: projectConfig?.name || "test-project",
|
|
19
21
|
uri: workspaceUri.toString()
|
|
20
22
|
};
|
|
21
23
|
let isInitialized = false;
|
|
@@ -34,6 +36,19 @@ export function createTestServices(workspace = "file:///test/workspace") {
|
|
|
34
36
|
workspaceFolders: [workspaceFolder]
|
|
35
37
|
});
|
|
36
38
|
await services.shared.workspace.WorkspaceManager.initializeWorkspace([workspaceFolder]);
|
|
39
|
+
if (projectConfig) {
|
|
40
|
+
const projectFolderUri = Utils.resolvePath(workspaceUri, "src");
|
|
41
|
+
services.shared.workspace.ProjectsManager.registerProject({
|
|
42
|
+
config: {
|
|
43
|
+
name: projectConfig?.name || "test-project",
|
|
44
|
+
title: projectConfig?.title || "Test Project",
|
|
45
|
+
contactPerson: projectConfig?.contactPerson || "Unknown",
|
|
46
|
+
imageAliases: projectConfig?.imageAliases || {},
|
|
47
|
+
exclude: projectConfig?.exclude || ["node_modules"]
|
|
48
|
+
},
|
|
49
|
+
folderUri: projectFolderUri
|
|
50
|
+
});
|
|
51
|
+
}
|
|
37
52
|
});
|
|
38
53
|
}
|
|
39
54
|
const addDocument = async (input, uri) => {
|
|
@@ -139,7 +154,7 @@ export async function createMultiProjectTestServices(data) {
|
|
|
139
154
|
services,
|
|
140
155
|
addDocument,
|
|
141
156
|
validateAll
|
|
142
|
-
} = createTestServices(workspace);
|
|
157
|
+
} = createTestServices({ workspace });
|
|
143
158
|
const projects = {};
|
|
144
159
|
for (const [name, files] of entries(data)) {
|
|
145
160
|
const folderUri = UriUtils.joinPath(URI.parse(workspace), "src", name);
|
package/dist/utils/stringHash.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { compareNatural, invariant } from "@likec4/core";
|
|
1
|
+
import { compareNatural, invariant } from "@likec4/core/utils";
|
|
2
2
|
import { filter, hasAtLeast, isTruthy, map, pipe, unique } from "remeda";
|
|
3
3
|
import { parsePath } from "ufo";
|
|
4
4
|
function commonAncestorPath(views, sep = "/") {
|
|
@@ -1,8 +1,7 @@
|
|
|
1
|
+
import { type LikeC4ProjectConfig } from '@likec4/config';
|
|
1
2
|
import type { NonEmptyReadonlyArray, ProjectId } from '@likec4/core';
|
|
2
3
|
import { type Cancellation, type FileSystemNode, type LangiumDocument, URI, WorkspaceCache } from 'langium';
|
|
3
|
-
import picomatch from 'picomatch';
|
|
4
4
|
import type { Tagged } from 'type-fest';
|
|
5
|
-
import { ProjectConfig } from '../config';
|
|
6
5
|
import type { LikeC4SharedServices } from '../module';
|
|
7
6
|
/**
|
|
8
7
|
* A tagged string that represents a project folder URI
|
|
@@ -12,24 +11,25 @@ export type ProjectFolder = Tagged<string, 'ProjectFolder'>;
|
|
|
12
11
|
export declare function ProjectFolder(folder: URI | string): ProjectFolder;
|
|
13
12
|
interface ProjectData {
|
|
14
13
|
id: ProjectId;
|
|
15
|
-
config:
|
|
14
|
+
config: LikeC4ProjectConfig;
|
|
16
15
|
folder: ProjectFolder;
|
|
17
16
|
folderUri: URI;
|
|
18
|
-
exclude?:
|
|
17
|
+
exclude?: (path: string) => boolean;
|
|
19
18
|
}
|
|
20
19
|
export interface Project {
|
|
21
20
|
id: ProjectId;
|
|
22
21
|
folderUri: URI;
|
|
23
|
-
config:
|
|
22
|
+
config: LikeC4ProjectConfig;
|
|
24
23
|
}
|
|
25
24
|
export declare class ProjectsManager {
|
|
25
|
+
#private;
|
|
26
26
|
protected services: LikeC4SharedServices;
|
|
27
27
|
/**
|
|
28
28
|
* The global project ID used for all documents
|
|
29
29
|
* that are not part of a specific project.
|
|
30
30
|
*/
|
|
31
31
|
static readonly DefaultProjectId: ProjectId;
|
|
32
|
-
static
|
|
32
|
+
private static DefaultProject;
|
|
33
33
|
/**
|
|
34
34
|
* The mapping between project config files and project IDs.
|
|
35
35
|
*/
|
|
@@ -41,20 +41,30 @@ export declare class ProjectsManager {
|
|
|
41
41
|
*/
|
|
42
42
|
private _projects;
|
|
43
43
|
private excludedDocuments;
|
|
44
|
-
private defaultGlobalProject;
|
|
44
|
+
private get defaultGlobalProject();
|
|
45
45
|
private reloadProjectsLimiter;
|
|
46
46
|
constructor(services: LikeC4SharedServices);
|
|
47
47
|
/**
|
|
48
48
|
* Returns:
|
|
49
|
+
* - configured default project ID if set
|
|
49
50
|
* - the default project ID if there are no projects.
|
|
50
51
|
* - the ID of the only project
|
|
51
52
|
* - undefined if there are multiple projects.
|
|
52
53
|
*/
|
|
53
54
|
get defaultProjectId(): ProjectId | undefined;
|
|
55
|
+
set defaultProjectId(id: ProjectId | undefined);
|
|
54
56
|
get all(): NonEmptyReadonlyArray<ProjectId>;
|
|
55
57
|
getProject(arg: ProjectId | LangiumDocument): Project;
|
|
58
|
+
/**
|
|
59
|
+
* Validates and ensures the project ID.
|
|
60
|
+
* If no project ID is specified, returns default project ID
|
|
61
|
+
* If there are multiple projects and default project is not set, throws an error
|
|
62
|
+
*/
|
|
56
63
|
ensureProjectId(projectId?: ProjectId | undefined): ProjectId;
|
|
57
64
|
hasMultipleProjects(): boolean;
|
|
65
|
+
/**
|
|
66
|
+
* Checks if the specified document should be excluded from processing.
|
|
67
|
+
*/
|
|
58
68
|
checkIfExcluded(document: LangiumDocument | URI | string): boolean;
|
|
59
69
|
/**
|
|
60
70
|
* Checks if it is a config file and it is not excluded by default exclude pattern
|
|
@@ -68,15 +78,19 @@ export declare class ProjectsManager {
|
|
|
68
78
|
* @param entry The file system entry to check
|
|
69
79
|
*/
|
|
70
80
|
loadConfigFile(entry: FileSystemNode): Promise<ProjectData | undefined>;
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
81
|
+
/**
|
|
82
|
+
* Registers (or reloads) likec4 project by config file or config object.
|
|
83
|
+
* If there is some project registered at same folder, it will be reloaded.
|
|
84
|
+
*/
|
|
85
|
+
registerProject(opts: URI | {
|
|
86
|
+
config: LikeC4ProjectConfig;
|
|
74
87
|
folderUri: URI | string;
|
|
75
88
|
}): Promise<ProjectData>;
|
|
76
89
|
belongsTo(document: LangiumDocument | URI | string): ProjectId;
|
|
77
90
|
reloadProjects(token?: Cancellation.CancellationToken): Promise<void>;
|
|
78
91
|
protected uniqueProjectId(name: string): ProjectId;
|
|
79
92
|
protected resetProjectIds(): void;
|
|
93
|
+
protected rebuidDocuments(): Promise<void>;
|
|
80
94
|
protected findProjectForDocument(documentUri: string): any;
|
|
81
95
|
protected get mappingsToProject(): WorkspaceCache<string, Pick<ProjectData, 'id' | 'config' | 'exclude'>>;
|
|
82
96
|
}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { isLikeC4Config, validateProjectConfig } from "@likec4/config";
|
|
2
|
+
import { BiMap, delay, invariant, memoizeProp, nonNullable } from "@likec4/core/utils";
|
|
2
3
|
import { loggable } from "@likec4/log";
|
|
3
4
|
import { deepEqual } from "fast-equals";
|
|
4
5
|
import {
|
|
@@ -15,7 +16,6 @@ import {
|
|
|
15
16
|
withoutProtocol,
|
|
16
17
|
withTrailingSlash
|
|
17
18
|
} from "ufo";
|
|
18
|
-
import { parseConfigJson, validateConfig } from "../config/index.js";
|
|
19
19
|
import { logger as mainLogger } from "../logger.js";
|
|
20
20
|
const logger = mainLogger.getChild("ProjectsManager");
|
|
21
21
|
function normalizeUri(uri) {
|
|
@@ -41,11 +41,19 @@ export class ProjectsManager {
|
|
|
41
41
|
* that are not part of a specific project.
|
|
42
42
|
*/
|
|
43
43
|
static DefaultProjectId = "default";
|
|
44
|
-
static
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
44
|
+
static DefaultProject = {
|
|
45
|
+
id: ProjectsManager.DefaultProjectId,
|
|
46
|
+
config: {
|
|
47
|
+
name: ProjectsManager.DefaultProjectId,
|
|
48
|
+
exclude: ["**/node_modules/**"]
|
|
49
|
+
},
|
|
50
|
+
exclude: picomatch("**/node_modules/**", { dot: true })
|
|
51
|
+
};
|
|
52
|
+
/**
|
|
53
|
+
* Configured default project ID.
|
|
54
|
+
* (it is used in CLI and Vite plugin)
|
|
55
|
+
*/
|
|
56
|
+
#defaultProjectId = void 0;
|
|
49
57
|
/**
|
|
50
58
|
* The mapping between project config files and project IDs.
|
|
51
59
|
*/
|
|
@@ -57,36 +65,56 @@ export class ProjectsManager {
|
|
|
57
65
|
*/
|
|
58
66
|
_projects = [];
|
|
59
67
|
excludedDocuments = /* @__PURE__ */ new WeakMap();
|
|
60
|
-
defaultGlobalProject
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
name: ProjectsManager.DefaultProjectId,
|
|
64
|
-
exclude: ["**/node_modules/**"]
|
|
65
|
-
},
|
|
66
|
-
exclude: picomatch("**/node_modules/**", { dot: true })
|
|
67
|
-
};
|
|
68
|
+
get defaultGlobalProject() {
|
|
69
|
+
return ProjectsManager.DefaultProject;
|
|
70
|
+
}
|
|
68
71
|
reloadProjectsLimiter = new PQueue({
|
|
69
72
|
concurrency: 1,
|
|
70
73
|
timeout: 2e4
|
|
71
74
|
});
|
|
72
75
|
/**
|
|
73
76
|
* Returns:
|
|
77
|
+
* - configured default project ID if set
|
|
74
78
|
* - the default project ID if there are no projects.
|
|
75
79
|
* - the ID of the only project
|
|
76
80
|
* - undefined if there are multiple projects.
|
|
77
81
|
*/
|
|
78
82
|
get defaultProjectId() {
|
|
83
|
+
if (this.#defaultProjectId) {
|
|
84
|
+
return this.#defaultProjectId;
|
|
85
|
+
}
|
|
79
86
|
if (this._projects.length > 1) {
|
|
80
87
|
return void 0;
|
|
81
88
|
}
|
|
82
89
|
return this._projects[0]?.id ?? ProjectsManager.DefaultProjectId;
|
|
83
90
|
}
|
|
91
|
+
set defaultProjectId(id) {
|
|
92
|
+
if (id === this.#defaultProjectId) {
|
|
93
|
+
return;
|
|
94
|
+
}
|
|
95
|
+
if (!id || id === ProjectsManager.DefaultProjectId) {
|
|
96
|
+
logger.debug`reset default project ID`;
|
|
97
|
+
this.#defaultProjectId = void 0;
|
|
98
|
+
return;
|
|
99
|
+
}
|
|
100
|
+
invariant(this._projects.find((p) => p.id === id), `Project "${id}" not found`);
|
|
101
|
+
logger.debug`set default project ID to ${id}`;
|
|
102
|
+
this.#defaultProjectId = id;
|
|
103
|
+
}
|
|
84
104
|
get all() {
|
|
85
105
|
if (hasAtLeast(this._projects, 1)) {
|
|
86
|
-
|
|
106
|
+
const ids = [
|
|
87
107
|
...map(this._projects, prop("id")),
|
|
88
108
|
ProjectsManager.DefaultProjectId
|
|
89
109
|
];
|
|
110
|
+
if (this.#defaultProjectId) {
|
|
111
|
+
const idx = ids.findIndex((p) => p === this.#defaultProjectId);
|
|
112
|
+
if (idx > 0) {
|
|
113
|
+
const [defaultProject] = ids.splice(idx, 1);
|
|
114
|
+
return [defaultProject, ...ids];
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
return ids;
|
|
90
118
|
}
|
|
91
119
|
return [ProjectsManager.DefaultProjectId];
|
|
92
120
|
}
|
|
@@ -116,6 +144,11 @@ export class ProjectsManager {
|
|
|
116
144
|
config
|
|
117
145
|
};
|
|
118
146
|
}
|
|
147
|
+
/**
|
|
148
|
+
* Validates and ensures the project ID.
|
|
149
|
+
* If no project ID is specified, returns default project ID
|
|
150
|
+
* If there are multiple projects and default project is not set, throws an error
|
|
151
|
+
*/
|
|
119
152
|
ensureProjectId(projectId) {
|
|
120
153
|
if (projectId === ProjectsManager.DefaultProjectId) {
|
|
121
154
|
return this.defaultProjectId ?? ProjectsManager.DefaultProjectId;
|
|
@@ -132,6 +165,9 @@ export class ProjectsManager {
|
|
|
132
165
|
hasMultipleProjects() {
|
|
133
166
|
return this._projects.length > 1;
|
|
134
167
|
}
|
|
168
|
+
/**
|
|
169
|
+
* Checks if the specified document should be excluded from processing.
|
|
170
|
+
*/
|
|
135
171
|
checkIfExcluded(document) {
|
|
136
172
|
if (typeof document === "string" || URI.isUri(document)) {
|
|
137
173
|
let docUriAsString = normalizeUri(document);
|
|
@@ -152,7 +188,7 @@ export class ProjectsManager {
|
|
|
152
188
|
*/
|
|
153
189
|
isConfigFile(entry) {
|
|
154
190
|
const filename = parseFilename(entry.toString(), { strict: false })?.toLowerCase();
|
|
155
|
-
const isConfigFile = !!filename &&
|
|
191
|
+
const isConfigFile = !!filename && isLikeC4Config(filename);
|
|
156
192
|
if (isConfigFile) {
|
|
157
193
|
if (this.defaultGlobalProject.exclude(entry.path)) {
|
|
158
194
|
logger.debug`exclude config file ${entry.path}`;
|
|
@@ -179,22 +215,25 @@ export class ProjectsManager {
|
|
|
179
215
|
|
|
180
216
|
${loggable(error)}`
|
|
181
217
|
);
|
|
182
|
-
logger.
|
|
218
|
+
logger.warn("Failed to register project at {uri}", { uri: entry.uri.toString(), error });
|
|
183
219
|
return void 0;
|
|
184
220
|
}
|
|
185
221
|
}
|
|
186
222
|
return void 0;
|
|
187
223
|
}
|
|
224
|
+
/**
|
|
225
|
+
* Registers (or reloads) likec4 project by config file or config object.
|
|
226
|
+
* If there is some project registered at same folder, it will be reloaded.
|
|
227
|
+
*/
|
|
188
228
|
async registerProject(opts) {
|
|
189
229
|
if (URI.isUri(opts)) {
|
|
190
230
|
const configFile = opts;
|
|
191
|
-
const
|
|
192
|
-
const config2 = parseConfigJson(cfg);
|
|
231
|
+
const config2 = await this.services.workspace.FileSystemProvider.loadProjectConfig(configFile);
|
|
193
232
|
const path = joinRelativeURL(configFile.path, "..");
|
|
194
233
|
const folderUri2 = configFile.with({ path });
|
|
195
234
|
return await this.registerProject({ config: config2, folderUri: folderUri2 });
|
|
196
235
|
}
|
|
197
|
-
const config = pickBy(
|
|
236
|
+
const config = pickBy(validateProjectConfig(opts.config), isTruthy);
|
|
198
237
|
const { folderUri } = opts;
|
|
199
238
|
const folder = ProjectFolder(folderUri);
|
|
200
239
|
let project = this._projects.find((p) => p.folder === folder);
|
|
@@ -278,7 +317,7 @@ ${loggable(error)}`
|
|
|
278
317
|
}
|
|
279
318
|
}
|
|
280
319
|
} catch (error) {
|
|
281
|
-
logger.error("Failed to
|
|
320
|
+
logger.error("Failed to scanProjectFiles, {folder}", { folder: folder.uri, error });
|
|
282
321
|
}
|
|
283
322
|
}
|
|
284
323
|
if (configFiles.length === 0 && this._projects.length !== 0) {
|
|
@@ -288,15 +327,13 @@ ${loggable(error)}`
|
|
|
288
327
|
this.projectIdToFolder.clear();
|
|
289
328
|
for (const entry of configFiles) {
|
|
290
329
|
try {
|
|
291
|
-
await this.
|
|
330
|
+
await this.loadConfigFile(entry);
|
|
292
331
|
} catch (error) {
|
|
293
|
-
logger.error("Failed to load config file", { error });
|
|
332
|
+
logger.error("Failed to load config file {uri}", { uri: entry.uri.toString(), error });
|
|
294
333
|
}
|
|
295
334
|
}
|
|
296
335
|
this.resetProjectIds();
|
|
297
|
-
|
|
298
|
-
logger.info("invalidate and rebuild documents {docs}", { docs: docs.length });
|
|
299
|
-
await this.services.workspace.DocumentBuilder.update(docs, []);
|
|
336
|
+
await this.rebuidDocuments();
|
|
300
337
|
});
|
|
301
338
|
}
|
|
302
339
|
uniqueProjectId(name) {
|
|
@@ -308,10 +345,18 @@ ${loggable(error)}`
|
|
|
308
345
|
return id;
|
|
309
346
|
}
|
|
310
347
|
resetProjectIds() {
|
|
348
|
+
if (this.#defaultProjectId && !this.projectIdToFolder.has(this.#defaultProjectId)) {
|
|
349
|
+
this.#defaultProjectId = void 0;
|
|
350
|
+
}
|
|
311
351
|
this.mappingsToProject.clear();
|
|
312
352
|
this.excludedDocuments = /* @__PURE__ */ new WeakMap();
|
|
313
353
|
this.services.workspace.LangiumDocuments.resetProjectIds();
|
|
314
354
|
}
|
|
355
|
+
async rebuidDocuments() {
|
|
356
|
+
const docs = this.services.workspace.LangiumDocuments.all.map((d) => d.uri).toArray();
|
|
357
|
+
logger.info("invalidate and rebuild all {docs} documents", { docs: docs.length });
|
|
358
|
+
await this.services.workspace.DocumentBuilder.update(docs, []);
|
|
359
|
+
}
|
|
315
360
|
findProjectForDocument(documentUri) {
|
|
316
361
|
return this.mappingsToProject.get(documentUri, () => {
|
|
317
362
|
const project = this._projects.find(({ folder }) => documentUri.startsWith(folder));
|
|
@@ -1,8 +1,9 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { invariant } from "@likec4/core";
|
|
2
2
|
import { DefaultWorkspaceManager } from "langium";
|
|
3
|
+
import { hasAtLeast } from "remeda";
|
|
3
4
|
import { URI } from "vscode-uri";
|
|
4
5
|
import * as BuiltIn from "../likec4lib.js";
|
|
5
|
-
import {
|
|
6
|
+
import { logWarnError } from "../logger.js";
|
|
6
7
|
export class LikeC4WorkspaceManager extends DefaultWorkspaceManager {
|
|
7
8
|
constructor(services) {
|
|
8
9
|
super(services);
|
|
@@ -29,7 +30,7 @@ export class LikeC4WorkspaceManager extends DefaultWorkspaceManager {
|
|
|
29
30
|
configFiles.push(...found);
|
|
30
31
|
this.services.workspace.FileSystemWatcher.watch(uri.fsPath);
|
|
31
32
|
} catch (error) {
|
|
32
|
-
|
|
33
|
+
logWarnError(error);
|
|
33
34
|
}
|
|
34
35
|
}
|
|
35
36
|
const projects = this.services.workspace.ProjectsManager;
|
|
@@ -37,7 +38,7 @@ export class LikeC4WorkspaceManager extends DefaultWorkspaceManager {
|
|
|
37
38
|
try {
|
|
38
39
|
await projects.loadConfigFile(entry);
|
|
39
40
|
} catch (error) {
|
|
40
|
-
|
|
41
|
+
logWarnError(error);
|
|
41
42
|
}
|
|
42
43
|
}
|
|
43
44
|
return await super.performStartup(folders);
|