@likec4/language-server 1.38.1 → 1.39.1
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
|
@@ -14,6 +14,7 @@ const searchResultSchema = z.array(
|
|
|
14
14
|
technology: z.string().nullable(),
|
|
15
15
|
shape: z.string(),
|
|
16
16
|
includedInViews: includedInViewsSchema,
|
|
17
|
+
metadata: z.record(z.string()),
|
|
17
18
|
tags: z.array(z.string())
|
|
18
19
|
}),
|
|
19
20
|
z.object({
|
|
@@ -26,6 +27,7 @@ const searchResultSchema = z.array(
|
|
|
26
27
|
technology: z.string().nullable(),
|
|
27
28
|
shape: z.string(),
|
|
28
29
|
includedInViews: includedInViewsSchema,
|
|
30
|
+
metadata: z.record(z.string()),
|
|
29
31
|
tags: z.array(z.string())
|
|
30
32
|
})
|
|
31
33
|
])
|
|
@@ -41,21 +43,22 @@ export const searchElement = likec4Tool({
|
|
|
41
43
|
Search LikeC4 elements and deployment nodes across all projects.
|
|
42
44
|
|
|
43
45
|
Query syntax (case-insensitive):
|
|
44
|
-
- Free text: matches id (FQN) or title
|
|
45
46
|
- kind:<value>: filters by kind
|
|
46
47
|
- shape:<value>: filters by shape
|
|
48
|
+
- meta:<key>: filters by having metadata with the given key
|
|
47
49
|
- #<value>: matches assigned tags
|
|
50
|
+
- Free text: matches id (FQN) or title
|
|
48
51
|
|
|
49
52
|
Request:
|
|
50
53
|
- search: string \u2014 at least 2 characters
|
|
51
54
|
|
|
52
55
|
Response (JSON object):
|
|
53
|
-
- found: Result[] - returns top 20 results
|
|
54
56
|
- total: number - total number of results
|
|
57
|
+
- found: Result[] - returns top 20 results
|
|
55
58
|
|
|
56
59
|
Result (discriminated union by "type"):
|
|
57
|
-
- type = "element": { id: string, name: string, kind: string, title: string, technology: string|null, shape: string, project: string, includedInViews: View[], tags: string[] }
|
|
58
|
-
- type = "deployment-node": { id: string, name: string, kind: string, title: string, technology: string|null, shape: string, project: string, includedInViews: View[], tags: string[] }
|
|
60
|
+
- type = "element": { id: string, name: string, kind: string, title: string, technology: string|null, shape: string, project: string, includedInViews: View[], tags: string[], metadata: Record<string, string> }
|
|
61
|
+
- type = "deployment-node": { id: string, name: string, kind: string, title: string, technology: string|null, shape: string, project: string, includedInViews: View[], tags: string[], metadata: Record<string, string> }
|
|
59
62
|
|
|
60
63
|
View (object) fields:
|
|
61
64
|
- id: string \u2014 view identifier
|
|
@@ -68,6 +71,7 @@ Notes:
|
|
|
68
71
|
|
|
69
72
|
Example response:
|
|
70
73
|
{
|
|
74
|
+
"total": 1,
|
|
71
75
|
"found": [
|
|
72
76
|
{
|
|
73
77
|
"type": "logical",
|
|
@@ -85,7 +89,8 @@ Example response:
|
|
|
85
89
|
"type": "element"
|
|
86
90
|
}
|
|
87
91
|
],
|
|
88
|
-
"tags": ["public"]
|
|
92
|
+
"tags": ["public"],
|
|
93
|
+
"metadata": {}
|
|
89
94
|
}
|
|
90
95
|
]
|
|
91
96
|
}
|
|
@@ -94,8 +99,8 @@ Example response:
|
|
|
94
99
|
search: z.string().min(2, "Search must be at least 2 characters long")
|
|
95
100
|
},
|
|
96
101
|
outputSchema: {
|
|
97
|
-
|
|
98
|
-
|
|
102
|
+
total: z.number(),
|
|
103
|
+
found: searchResultSchema
|
|
99
104
|
}
|
|
100
105
|
}, async (languageServices, args) => {
|
|
101
106
|
const projects = languageServices.projects();
|
|
@@ -104,14 +109,22 @@ Example response:
|
|
|
104
109
|
let predicate;
|
|
105
110
|
if (search.startsWith("kind:")) {
|
|
106
111
|
search = search.slice(5);
|
|
107
|
-
|
|
112
|
+
logger.debug("search by kind: {search}", { search });
|
|
113
|
+
predicate = (el) => el.kind.toLowerCase() === search;
|
|
108
114
|
} else if (search.startsWith("shape:")) {
|
|
109
115
|
search = search.slice(6);
|
|
110
|
-
|
|
116
|
+
logger.debug("search by shape: {search}", { search });
|
|
117
|
+
predicate = (el) => el.shape.toLowerCase() === search;
|
|
118
|
+
} else if (search.startsWith("meta:")) {
|
|
119
|
+
search = search.slice(5);
|
|
120
|
+
logger.debug("search by metadata: {search}", { search });
|
|
121
|
+
predicate = (el) => !!el.getMetadata(search);
|
|
111
122
|
} else if (search.startsWith("#")) {
|
|
112
123
|
search = search.slice(1);
|
|
124
|
+
logger.debug("search by tag: {search}", { search });
|
|
113
125
|
predicate = (el) => el.tags.some((tag) => tag.toLowerCase().includes(search));
|
|
114
126
|
} else {
|
|
127
|
+
logger.debug("search by id/title: {search}", { search });
|
|
115
128
|
predicate = (el) => el.id.toLowerCase().includes(search) || el.title.toLowerCase().includes(search);
|
|
116
129
|
}
|
|
117
130
|
for (const project of projects) {
|
|
@@ -128,6 +141,7 @@ Example response:
|
|
|
128
141
|
technology: el.technology,
|
|
129
142
|
shape: el.shape,
|
|
130
143
|
tags: [...el.tags],
|
|
144
|
+
metadata: el.getMetadata(),
|
|
131
145
|
includedInViews: includedInViews(el.views())
|
|
132
146
|
});
|
|
133
147
|
}
|
|
@@ -142,6 +156,7 @@ Example response:
|
|
|
142
156
|
technology: el.technology,
|
|
143
157
|
shape: el.shape,
|
|
144
158
|
tags: [...el.tags],
|
|
159
|
+
metadata: el.getMetadata(),
|
|
145
160
|
includedInViews: includedInViews(el.views())
|
|
146
161
|
});
|
|
147
162
|
}
|
|
@@ -150,7 +165,7 @@ Example response:
|
|
|
150
165
|
}
|
|
151
166
|
}
|
|
152
167
|
return {
|
|
153
|
-
|
|
154
|
-
|
|
168
|
+
total: found.length,
|
|
169
|
+
found: found.slice(0, 20)
|
|
155
170
|
};
|
|
156
171
|
});
|
package/dist/mcp/utils.js
CHANGED
|
@@ -14,7 +14,7 @@ export function likec4Tool(config, cb) {
|
|
|
14
14
|
}
|
|
15
15
|
function mkcallTool(name, languageServices, cb) {
|
|
16
16
|
const tool = cb.bind(null, languageServices);
|
|
17
|
-
return async function callTool(args, extra) {
|
|
17
|
+
return (async function callTool(args, extra) {
|
|
18
18
|
logger.debug("Calling tool {name}, args: {args}", { name, args });
|
|
19
19
|
try {
|
|
20
20
|
const result = await tool.call(null, args, extra);
|
|
@@ -43,5 +43,5 @@ function mkcallTool(name, languageServices, cb) {
|
|
|
43
43
|
isError: true
|
|
44
44
|
};
|
|
45
45
|
}
|
|
46
|
-
};
|
|
46
|
+
});
|
|
47
47
|
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import * as c4 from '@likec4/core';
|
|
2
|
-
import { MultiMap } from '@likec4/core';
|
|
1
|
+
import type * as c4 from '@likec4/core';
|
|
2
|
+
import { MultiMap } from '@likec4/core/utils';
|
|
3
3
|
import type { ParsedAstDeployment, ParsedAstDeploymentRelation, ParsedAstElement, ParsedAstRelation, ParsedAstSpecification, ParsedLikeC4LangiumDocument } from '../../ast';
|
|
4
4
|
/**
|
|
5
5
|
* The `MergedSpecification` class is responsible for merging multiple parsed
|
|
@@ -1,8 +1,5 @@
|
|
|
1
|
-
import
|
|
2
|
-
import { MultiMap } from "@likec4/core";
|
|
3
|
-
import {
|
|
4
|
-
FqnRef
|
|
5
|
-
} from "@likec4/core/types";
|
|
1
|
+
import { FqnRef } from "@likec4/core/types";
|
|
2
|
+
import { MultiMap, nameFromFqn } from "@likec4/core/utils";
|
|
6
3
|
import {
|
|
7
4
|
isBoolean,
|
|
8
5
|
isEmpty,
|
|
@@ -89,7 +86,7 @@ export class MergedSpecification {
|
|
|
89
86
|
textSize ??= __kind.style.textSize;
|
|
90
87
|
description ??= __kind.description;
|
|
91
88
|
links ??= __kind.links;
|
|
92
|
-
title = title ===
|
|
89
|
+
title = title === nameFromFqn(id) && __kind.title ? __kind.title : title;
|
|
93
90
|
return {
|
|
94
91
|
...color && { color },
|
|
95
92
|
...shape && { shape },
|
|
@@ -177,7 +174,7 @@ export class MergedSpecification {
|
|
|
177
174
|
...rest
|
|
178
175
|
} = parsed;
|
|
179
176
|
description ??= __kind.description;
|
|
180
|
-
title = title ===
|
|
177
|
+
title = title === nameFromFqn(parsed.id) && __kind.title ? __kind.title : title;
|
|
181
178
|
return {
|
|
182
179
|
...rest,
|
|
183
180
|
...{ title },
|
|
@@ -1,8 +1,7 @@
|
|
|
1
|
-
import * as c4 from '@likec4/core';
|
|
1
|
+
import type * as c4 from '@likec4/core';
|
|
2
2
|
import { type MultiMap } from '@likec4/core';
|
|
3
|
-
import type { URI } from 'langium';
|
|
4
3
|
import type { ParsedLikeC4LangiumDocument } from '../../ast';
|
|
5
|
-
import type {
|
|
4
|
+
import type { Project } from '../../workspace/ProjectsManager';
|
|
6
5
|
export type BuildModelData = {
|
|
7
6
|
data: c4.ParsedLikeC4ModelData;
|
|
8
7
|
imports: MultiMap<c4.ProjectId, c4.Fqn, Set<c4.Fqn>>;
|
|
@@ -14,8 +13,4 @@ export type BuildModelData = {
|
|
|
14
13
|
* This function builds a model from all documents, merging the specifications
|
|
15
14
|
* and globals, and applying the extends to the elements.
|
|
16
15
|
*/
|
|
17
|
-
export declare function buildModelData(project:
|
|
18
|
-
id: c4.ProjectId;
|
|
19
|
-
folderUri: URI;
|
|
20
|
-
config: Readonly<ProjectConfig>;
|
|
21
|
-
}, docs: ReadonlyArray<ParsedLikeC4LangiumDocument>): BuildModelData;
|
|
16
|
+
export declare function buildModelData(project: Project, docs: ReadonlyArray<ParsedLikeC4LangiumDocument>): BuildModelData;
|
|
@@ -1,12 +1,15 @@
|
|
|
1
|
-
import * as c4 from "@likec4/core";
|
|
2
1
|
import {
|
|
3
2
|
computeColorValues,
|
|
4
3
|
isDeploymentNode,
|
|
5
|
-
isGlobalFqn
|
|
6
|
-
parentFqn,
|
|
7
|
-
sortByFqnHierarchically
|
|
4
|
+
isGlobalFqn
|
|
8
5
|
} from "@likec4/core";
|
|
9
6
|
import { resolveRulesExtendedViews } from "@likec4/core/compute-view";
|
|
7
|
+
import { _stage, _type, FqnRef } from "@likec4/core/types";
|
|
8
|
+
import {
|
|
9
|
+
compareNatural,
|
|
10
|
+
parentFqn,
|
|
11
|
+
sortByFqnHierarchically
|
|
12
|
+
} from "@likec4/core/utils";
|
|
10
13
|
import {
|
|
11
14
|
filter,
|
|
12
15
|
flatMap,
|
|
@@ -69,7 +72,7 @@ export function buildModelData(project, docs) {
|
|
|
69
72
|
flatMap((d) => map(d.c4Relations, c4Specification.toModelRelation)),
|
|
70
73
|
filter((rel) => {
|
|
71
74
|
if (!rel) return false;
|
|
72
|
-
const source =
|
|
75
|
+
const source = FqnRef.flatten(rel.source), target = FqnRef.flatten(rel.target);
|
|
73
76
|
if (isNullish(elements[source]) && !isGlobalFqn(source) || isNullish(elements[target]) && !isGlobalFqn(target)) {
|
|
74
77
|
logger.debug`Invalid relation ${rel.id}
|
|
75
78
|
source: ${source} resolved: ${!!elements[source]}
|
|
@@ -143,7 +146,7 @@ export function buildModelData(project, docs) {
|
|
|
143
146
|
// model should include discriminant __
|
|
144
147
|
...model
|
|
145
148
|
} = parsedAstView;
|
|
146
|
-
if (parsedAstView[
|
|
149
|
+
if (parsedAstView[_type] === "element" && isNullish(title) && "viewOf" in parsedAstView) {
|
|
147
150
|
title = elements[parsedAstView.viewOf]?.title ?? null;
|
|
148
151
|
}
|
|
149
152
|
if (isNullish(title) && id === "index") {
|
|
@@ -151,7 +154,7 @@ export function buildModelData(project, docs) {
|
|
|
151
154
|
}
|
|
152
155
|
return {
|
|
153
156
|
...model,
|
|
154
|
-
[
|
|
157
|
+
[_stage]: "parsed",
|
|
155
158
|
docUri,
|
|
156
159
|
description,
|
|
157
160
|
title,
|
|
@@ -167,8 +170,8 @@ export function buildModelData(project, docs) {
|
|
|
167
170
|
);
|
|
168
171
|
if (!parsedViews.some((v) => v.id === "index")) {
|
|
169
172
|
parsedViews.unshift({
|
|
170
|
-
[
|
|
171
|
-
[
|
|
173
|
+
[_stage]: "parsed",
|
|
174
|
+
[_type]: "element",
|
|
172
175
|
id: "index",
|
|
173
176
|
title: "Landscape view",
|
|
174
177
|
description: null,
|
|
@@ -192,7 +195,7 @@ export function buildModelData(project, docs) {
|
|
|
192
195
|
);
|
|
193
196
|
return {
|
|
194
197
|
data: {
|
|
195
|
-
[
|
|
198
|
+
[_stage]: "parsed",
|
|
196
199
|
projectId: project.id,
|
|
197
200
|
project: {
|
|
198
201
|
id: project.id,
|
|
@@ -207,7 +210,7 @@ export function buildModelData(project, docs) {
|
|
|
207
210
|
style
|
|
208
211
|
})),
|
|
209
212
|
deployments: c4Specification.specs.deployments,
|
|
210
|
-
...metadataKeys.size > 0 && { metadataKeys: [...metadataKeys].sort(
|
|
213
|
+
...metadataKeys.size > 0 && { metadataKeys: [...metadataKeys].sort(compareNatural) },
|
|
211
214
|
customColors
|
|
212
215
|
},
|
|
213
216
|
elements,
|
|
@@ -6,7 +6,7 @@ import { CancellationToken } from 'vscode-jsonrpc';
|
|
|
6
6
|
import type { LikeC4Services } from '../module';
|
|
7
7
|
import { ADisposable } from '../utils';
|
|
8
8
|
type ModelParsedListener = (docs: URI[]) => void;
|
|
9
|
-
export interface LikeC4ModelBuilder {
|
|
9
|
+
export interface LikeC4ModelBuilder extends Disposable {
|
|
10
10
|
parseModel(projectId?: c4.ProjectId | undefined, cancelToken?: CancellationToken): Promise<LikeC4Model.Parsed | null>;
|
|
11
11
|
unsafeSyncBuildModel(projectId: c4.ProjectId): LikeC4Model.Computed;
|
|
12
12
|
buildLikeC4Model(projectId?: c4.ProjectId | undefined, cancelToken?: CancellationToken): Promise<LikeC4Model.Computed>;
|
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { splitGlobalFqn } from "@likec4/core";
|
|
2
|
+
import { ifilter, invariant, toArray } from "@likec4/core/utils";
|
|
2
3
|
import { loggable } from "@likec4/log";
|
|
3
4
|
import { AstUtils, DocumentState, GrammarUtils } from "langium";
|
|
4
5
|
import { flatMap, isString, pipe } from "remeda";
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { ProjectId } from '@likec4/core';
|
|
2
2
|
import { type LangiumDocument, type Stream } from 'langium';
|
|
3
|
-
import type
|
|
3
|
+
import { type ParsedLikeC4LangiumDocument } from '../ast';
|
|
4
4
|
import type { LikeC4Services } from '../module';
|
|
5
5
|
import { BaseParser } from './parser/Base';
|
|
6
6
|
export type ModelParsedListener = () => void;
|
|
@@ -55,11 +55,7 @@ declare const DocumentParserFromMixins: {
|
|
|
55
55
|
isValid: import("../validation").IsValidFn;
|
|
56
56
|
readonly services: LikeC4Services;
|
|
57
57
|
readonly doc: ParsedLikeC4LangiumDocument;
|
|
58
|
-
get project():
|
|
59
|
-
id: ProjectId;
|
|
60
|
-
folderUri: ProjectId;
|
|
61
|
-
config: Readonly<import("../config").ProjectConfig>;
|
|
62
|
-
};
|
|
58
|
+
get project(): import("../workspace").Project;
|
|
63
59
|
resolveFqn(node: import("../generated/ast").FqnReferenceable): ProjectId;
|
|
64
60
|
getAstNodePath(node: ProjectId): any;
|
|
65
61
|
getMetadata(metadataAstNode: import("../generated/ast").MetadataProperty | undefined): {
|
|
@@ -75,6 +71,7 @@ declare const DocumentParserFromMixins: {
|
|
|
75
71
|
convertLinks(source?: import("../generated/ast").LinkProperty["$container"]): ProjectId[] | undefined;
|
|
76
72
|
parseLinks(source?: import("../generated/ast").LinkProperty["$container"]): ProjectId[] | undefined;
|
|
77
73
|
parseIconProperty(prop: import("../generated/ast").IconProperty | undefined): ProjectId | undefined;
|
|
74
|
+
parseImageAlias(value: string): string | undefined;
|
|
78
75
|
parseColorLiteral(astNode: import("../generated/ast").ColorLiteral): ProjectId | undefined;
|
|
79
76
|
parseElementStyle(elementProps: Array<import("../generated/ast").ElementProperty> | import("../generated/ast").ElementStyleProperty | undefined): import("../ast").ParsedElementStyle;
|
|
80
77
|
parseStyleProps(styleProps: Array<import("../generated/ast").StyleProperty> | undefined): import("../ast").ParsedElementStyle;
|
|
@@ -148,11 +145,7 @@ declare const DocumentParserFromMixins: {
|
|
|
148
145
|
isValid: import("../validation").IsValidFn;
|
|
149
146
|
readonly services: LikeC4Services;
|
|
150
147
|
readonly doc: ParsedLikeC4LangiumDocument;
|
|
151
|
-
get project():
|
|
152
|
-
id: ProjectId;
|
|
153
|
-
folderUri: ProjectId;
|
|
154
|
-
config: Readonly<import("../config").ProjectConfig>;
|
|
155
|
-
};
|
|
148
|
+
get project(): import("../workspace").Project;
|
|
156
149
|
resolveFqn(node: import("../generated/ast").FqnReferenceable): ProjectId;
|
|
157
150
|
getAstNodePath(node: ProjectId): any;
|
|
158
151
|
getMetadata(metadataAstNode: import("../generated/ast").MetadataProperty | undefined): {
|
|
@@ -168,6 +161,7 @@ declare const DocumentParserFromMixins: {
|
|
|
168
161
|
convertLinks(source?: import("../generated/ast").LinkProperty["$container"]): ProjectId[] | undefined;
|
|
169
162
|
parseLinks(source?: import("../generated/ast").LinkProperty["$container"]): ProjectId[] | undefined;
|
|
170
163
|
parseIconProperty(prop: import("../generated/ast").IconProperty | undefined): ProjectId | undefined;
|
|
164
|
+
parseImageAlias(value: string): string | undefined;
|
|
171
165
|
parseColorLiteral(astNode: import("../generated/ast").ColorLiteral): ProjectId | undefined;
|
|
172
166
|
parseElementStyle(elementProps: Array<import("../generated/ast").ElementProperty> | import("../generated/ast").ElementStyleProperty | undefined): import("../ast").ParsedElementStyle;
|
|
173
167
|
parseStyleProps(styleProps: Array<import("../generated/ast").StyleProperty> | undefined): import("../ast").ParsedElementStyle;
|
|
@@ -203,11 +197,7 @@ declare const DocumentParserFromMixins: {
|
|
|
203
197
|
isValid: import("../validation").IsValidFn;
|
|
204
198
|
readonly services: LikeC4Services;
|
|
205
199
|
readonly doc: ParsedLikeC4LangiumDocument;
|
|
206
|
-
get project():
|
|
207
|
-
id: ProjectId;
|
|
208
|
-
folderUri: ProjectId;
|
|
209
|
-
config: Readonly<import("../config").ProjectConfig>;
|
|
210
|
-
};
|
|
200
|
+
get project(): import("../workspace").Project;
|
|
211
201
|
resolveFqn(node: import("../generated/ast").FqnReferenceable): ProjectId;
|
|
212
202
|
getAstNodePath(node: ProjectId): any;
|
|
213
203
|
getMetadata(metadataAstNode: import("../generated/ast").MetadataProperty | undefined): {
|
|
@@ -223,6 +213,7 @@ declare const DocumentParserFromMixins: {
|
|
|
223
213
|
convertLinks(source?: import("../generated/ast").LinkProperty["$container"]): ProjectId[] | undefined;
|
|
224
214
|
parseLinks(source?: import("../generated/ast").LinkProperty["$container"]): ProjectId[] | undefined;
|
|
225
215
|
parseIconProperty(prop: import("../generated/ast").IconProperty | undefined): ProjectId | undefined;
|
|
216
|
+
parseImageAlias(value: string): string | undefined;
|
|
226
217
|
parseColorLiteral(astNode: import("../generated/ast").ColorLiteral): ProjectId | undefined;
|
|
227
218
|
parseElementStyle(elementProps: Array<import("../generated/ast").ElementProperty> | import("../generated/ast").ElementStyleProperty | undefined): import("../ast").ParsedElementStyle;
|
|
228
219
|
parseStyleProps(styleProps: Array<import("../generated/ast").StyleProperty> | undefined): import("../ast").ParsedElementStyle;
|
|
@@ -272,11 +263,7 @@ declare const DocumentParserFromMixins: {
|
|
|
272
263
|
isValid: import("../validation").IsValidFn;
|
|
273
264
|
readonly services: LikeC4Services;
|
|
274
265
|
readonly doc: ParsedLikeC4LangiumDocument;
|
|
275
|
-
get project():
|
|
276
|
-
id: ProjectId;
|
|
277
|
-
folderUri: ProjectId;
|
|
278
|
-
config: Readonly<import("../config").ProjectConfig>;
|
|
279
|
-
};
|
|
266
|
+
get project(): import("../workspace").Project;
|
|
280
267
|
resolveFqn(node: import("../generated/ast").FqnReferenceable): ProjectId;
|
|
281
268
|
getAstNodePath(node: ProjectId): any;
|
|
282
269
|
getMetadata(metadataAstNode: import("../generated/ast").MetadataProperty | undefined): {
|
|
@@ -292,6 +279,7 @@ declare const DocumentParserFromMixins: {
|
|
|
292
279
|
convertLinks(source?: import("../generated/ast").LinkProperty["$container"]): ProjectId[] | undefined;
|
|
293
280
|
parseLinks(source?: import("../generated/ast").LinkProperty["$container"]): ProjectId[] | undefined;
|
|
294
281
|
parseIconProperty(prop: import("../generated/ast").IconProperty | undefined): ProjectId | undefined;
|
|
282
|
+
parseImageAlias(value: string): string | undefined;
|
|
295
283
|
parseColorLiteral(astNode: import("../generated/ast").ColorLiteral): ProjectId | undefined;
|
|
296
284
|
parseElementStyle(elementProps: Array<import("../generated/ast").ElementProperty> | import("../generated/ast").ElementStyleProperty | undefined): import("../ast").ParsedElementStyle;
|
|
297
285
|
parseStyleProps(styleProps: Array<import("../generated/ast").StyleProperty> | undefined): import("../ast").ParsedElementStyle;
|
|
@@ -334,11 +322,7 @@ declare const DocumentParserFromMixins: {
|
|
|
334
322
|
isValid: import("../validation").IsValidFn;
|
|
335
323
|
readonly services: LikeC4Services;
|
|
336
324
|
readonly doc: ParsedLikeC4LangiumDocument;
|
|
337
|
-
get project():
|
|
338
|
-
id: ProjectId;
|
|
339
|
-
folderUri: ProjectId;
|
|
340
|
-
config: Readonly<import("../config").ProjectConfig>;
|
|
341
|
-
};
|
|
325
|
+
get project(): import("../workspace").Project;
|
|
342
326
|
resolveFqn(node: import("../generated/ast").FqnReferenceable): ProjectId;
|
|
343
327
|
getAstNodePath(node: ProjectId): any;
|
|
344
328
|
getMetadata(metadataAstNode: import("../generated/ast").MetadataProperty | undefined): {
|
|
@@ -354,6 +338,7 @@ declare const DocumentParserFromMixins: {
|
|
|
354
338
|
convertLinks(source?: import("../generated/ast").LinkProperty["$container"]): ProjectId[] | undefined;
|
|
355
339
|
parseLinks(source?: import("../generated/ast").LinkProperty["$container"]): ProjectId[] | undefined;
|
|
356
340
|
parseIconProperty(prop: import("../generated/ast").IconProperty | undefined): ProjectId | undefined;
|
|
341
|
+
parseImageAlias(value: string): string | undefined;
|
|
357
342
|
parseColorLiteral(astNode: import("../generated/ast").ColorLiteral): ProjectId | undefined;
|
|
358
343
|
parseElementStyle(elementProps: Array<import("../generated/ast").ElementProperty> | import("../generated/ast").ElementStyleProperty | undefined): import("../ast").ParsedElementStyle;
|
|
359
344
|
parseStyleProps(styleProps: Array<import("../generated/ast").StyleProperty> | undefined): import("../ast").ParsedElementStyle;
|
|
@@ -404,11 +389,7 @@ declare const DocumentParserFromMixins: {
|
|
|
404
389
|
isValid: import("../validation").IsValidFn;
|
|
405
390
|
readonly services: LikeC4Services;
|
|
406
391
|
readonly doc: ParsedLikeC4LangiumDocument;
|
|
407
|
-
get project():
|
|
408
|
-
id: ProjectId;
|
|
409
|
-
folderUri: ProjectId;
|
|
410
|
-
config: Readonly<import("../config").ProjectConfig>;
|
|
411
|
-
};
|
|
392
|
+
get project(): import("../workspace").Project;
|
|
412
393
|
resolveFqn(node: import("../generated/ast").FqnReferenceable): ProjectId;
|
|
413
394
|
getAstNodePath(node: ProjectId): any;
|
|
414
395
|
getMetadata(metadataAstNode: import("../generated/ast").MetadataProperty | undefined): {
|
|
@@ -424,6 +405,7 @@ declare const DocumentParserFromMixins: {
|
|
|
424
405
|
convertLinks(source?: import("../generated/ast").LinkProperty["$container"]): ProjectId[] | undefined;
|
|
425
406
|
parseLinks(source?: import("../generated/ast").LinkProperty["$container"]): ProjectId[] | undefined;
|
|
426
407
|
parseIconProperty(prop: import("../generated/ast").IconProperty | undefined): ProjectId | undefined;
|
|
408
|
+
parseImageAlias(value: string): string | undefined;
|
|
427
409
|
parseColorLiteral(astNode: import("../generated/ast").ColorLiteral): ProjectId | undefined;
|
|
428
410
|
parseElementStyle(elementProps: Array<import("../generated/ast").ElementProperty> | import("../generated/ast").ElementStyleProperty | undefined): import("../ast").ParsedElementStyle;
|
|
429
411
|
parseStyleProps(styleProps: Array<import("../generated/ast").StyleProperty> | undefined): import("../ast").ParsedElementStyle;
|
|
@@ -467,11 +449,7 @@ declare const DocumentParserFromMixins: {
|
|
|
467
449
|
isValid: import("../validation").IsValidFn;
|
|
468
450
|
readonly services: LikeC4Services;
|
|
469
451
|
readonly doc: ParsedLikeC4LangiumDocument;
|
|
470
|
-
get project():
|
|
471
|
-
id: ProjectId;
|
|
472
|
-
folderUri: ProjectId;
|
|
473
|
-
config: Readonly<import("../config").ProjectConfig>;
|
|
474
|
-
};
|
|
452
|
+
get project(): import("../workspace").Project;
|
|
475
453
|
resolveFqn(node: import("../generated/ast").FqnReferenceable): ProjectId;
|
|
476
454
|
getAstNodePath(node: ProjectId): any;
|
|
477
455
|
getMetadata(metadataAstNode: import("../generated/ast").MetadataProperty | undefined): {
|
|
@@ -487,6 +465,7 @@ declare const DocumentParserFromMixins: {
|
|
|
487
465
|
convertLinks(source?: import("../generated/ast").LinkProperty["$container"]): ProjectId[] | undefined;
|
|
488
466
|
parseLinks(source?: import("../generated/ast").LinkProperty["$container"]): ProjectId[] | undefined;
|
|
489
467
|
parseIconProperty(prop: import("../generated/ast").IconProperty | undefined): ProjectId | undefined;
|
|
468
|
+
parseImageAlias(value: string): string | undefined;
|
|
490
469
|
parseColorLiteral(astNode: import("../generated/ast").ColorLiteral): ProjectId | undefined;
|
|
491
470
|
parseElementStyle(elementProps: Array<import("../generated/ast").ElementProperty> | import("../generated/ast").ElementStyleProperty | undefined): import("../ast").ParsedElementStyle;
|
|
492
471
|
parseStyleProps(styleProps: Array<import("../generated/ast").StyleProperty> | undefined): import("../ast").ParsedElementStyle;
|
|
@@ -510,11 +489,7 @@ declare const DocumentParserFromMixins: {
|
|
|
510
489
|
isValid: import("../validation").IsValidFn;
|
|
511
490
|
readonly services: LikeC4Services;
|
|
512
491
|
readonly doc: ParsedLikeC4LangiumDocument;
|
|
513
|
-
get project():
|
|
514
|
-
id: ProjectId;
|
|
515
|
-
folderUri: ProjectId;
|
|
516
|
-
config: Readonly<import("../config").ProjectConfig>;
|
|
517
|
-
};
|
|
492
|
+
get project(): import("../workspace").Project;
|
|
518
493
|
resolveFqn(node: import("../generated/ast").FqnReferenceable): ProjectId;
|
|
519
494
|
getAstNodePath(node: ProjectId): any;
|
|
520
495
|
getMetadata(metadataAstNode: import("../generated/ast").MetadataProperty | undefined): {
|
|
@@ -530,6 +505,7 @@ declare const DocumentParserFromMixins: {
|
|
|
530
505
|
convertLinks(source?: import("../generated/ast").LinkProperty["$container"]): ProjectId[] | undefined;
|
|
531
506
|
parseLinks(source?: import("../generated/ast").LinkProperty["$container"]): ProjectId[] | undefined;
|
|
532
507
|
parseIconProperty(prop: import("../generated/ast").IconProperty | undefined): ProjectId | undefined;
|
|
508
|
+
parseImageAlias(value: string): string | undefined;
|
|
533
509
|
parseColorLiteral(astNode: import("../generated/ast").ColorLiteral): ProjectId | undefined;
|
|
534
510
|
parseElementStyle(elementProps: Array<import("../generated/ast").ElementProperty> | import("../generated/ast").ElementStyleProperty | undefined): import("../ast").ParsedElementStyle;
|
|
535
511
|
parseStyleProps(styleProps: Array<import("../generated/ast").StyleProperty> | undefined): import("../ast").ParsedElementStyle;
|
|
@@ -568,11 +544,7 @@ declare const DocumentParserFromMixins: {
|
|
|
568
544
|
isValid: import("../validation").IsValidFn;
|
|
569
545
|
readonly services: LikeC4Services;
|
|
570
546
|
readonly doc: ParsedLikeC4LangiumDocument;
|
|
571
|
-
get project():
|
|
572
|
-
id: ProjectId;
|
|
573
|
-
folderUri: ProjectId;
|
|
574
|
-
config: Readonly<import("../config").ProjectConfig>;
|
|
575
|
-
};
|
|
547
|
+
get project(): import("../workspace").Project;
|
|
576
548
|
resolveFqn(node: import("../generated/ast").FqnReferenceable): ProjectId;
|
|
577
549
|
getAstNodePath(node: ProjectId): any;
|
|
578
550
|
getMetadata(metadataAstNode: import("../generated/ast").MetadataProperty | undefined): {
|
|
@@ -588,6 +560,7 @@ declare const DocumentParserFromMixins: {
|
|
|
588
560
|
convertLinks(source?: import("../generated/ast").LinkProperty["$container"]): ProjectId[] | undefined;
|
|
589
561
|
parseLinks(source?: import("../generated/ast").LinkProperty["$container"]): ProjectId[] | undefined;
|
|
590
562
|
parseIconProperty(prop: import("../generated/ast").IconProperty | undefined): ProjectId | undefined;
|
|
563
|
+
parseImageAlias(value: string): string | undefined;
|
|
591
564
|
parseColorLiteral(astNode: import("../generated/ast").ColorLiteral): ProjectId | undefined;
|
|
592
565
|
parseElementStyle(elementProps: Array<import("../generated/ast").ElementProperty> | import("../generated/ast").ElementStyleProperty | undefined): import("../ast").ParsedElementStyle;
|
|
593
566
|
parseStyleProps(styleProps: Array<import("../generated/ast").StyleProperty> | undefined): import("../ast").ParsedElementStyle;
|
|
@@ -1,8 +1,9 @@
|
|
|
1
|
-
import { DefaultWeakMap, MultiMap } from "@likec4/core/utils";
|
|
1
|
+
import { DefaultWeakMap, invariant, MultiMap } from "@likec4/core/utils";
|
|
2
2
|
import { loggable } from "@likec4/log";
|
|
3
3
|
import { DocumentState } from "langium";
|
|
4
4
|
import { pipe } from "remeda";
|
|
5
5
|
import { DiagnosticSeverity } from "vscode-languageserver-types";
|
|
6
|
+
import { isLikeC4LangiumDocument } from "../ast.js";
|
|
6
7
|
import { isLikeC4Builtin } from "../likec4lib.js";
|
|
7
8
|
import { logger as rootLogger } from "../logger.js";
|
|
8
9
|
import { BaseParser } from "./parser/Base.js";
|
|
@@ -73,11 +74,20 @@ export class LikeC4ModelParser {
|
|
|
73
74
|
}
|
|
74
75
|
forDocument(doc) {
|
|
75
76
|
if (doc.state < DocumentState.Linked) {
|
|
76
|
-
logger.warn(`Document
|
|
77
|
+
logger.warn(`Document {doc} is not linked`, { doc: doc.uri.toString() });
|
|
77
78
|
}
|
|
78
79
|
return this.cachedParsers.get(doc);
|
|
79
80
|
}
|
|
80
81
|
createParser(doc) {
|
|
82
|
+
invariant(isLikeC4LangiumDocument(doc), `Document ${doc.uri.toString()} is not a LikeC4 document`);
|
|
83
|
+
if (doc.likec4ProjectId) {
|
|
84
|
+
logger.debug(`create parser {projectId} document {doc}`, {
|
|
85
|
+
projectId: doc.likec4ProjectId,
|
|
86
|
+
doc: doc.uri.toString()
|
|
87
|
+
});
|
|
88
|
+
} else {
|
|
89
|
+
logger.warn(`create parser for document without project {doc}`, { doc: doc.uri.toString() });
|
|
90
|
+
}
|
|
81
91
|
const props = {
|
|
82
92
|
c4Specification: {
|
|
83
93
|
tags: {},
|
|
@@ -110,7 +120,7 @@ export class LikeC4ModelParser {
|
|
|
110
120
|
parser.parseDeployment();
|
|
111
121
|
parser.parseViews();
|
|
112
122
|
} catch (e) {
|
|
113
|
-
logger.error(`Error parsing document
|
|
123
|
+
logger.error(`Error parsing document {doc}`, { doc: doc.uri.toString(), error: e });
|
|
114
124
|
}
|
|
115
125
|
return parser;
|
|
116
126
|
}
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import type * as c4 from '@likec4/core';
|
|
2
2
|
import { type MarkdownOrString } from '@likec4/core';
|
|
3
|
-
import type { AstNode
|
|
3
|
+
import type { AstNode } from 'langium';
|
|
4
4
|
import { type ParsedElementStyle, type ParsedLikeC4LangiumDocument, ast } from '../../ast';
|
|
5
|
-
import type { ProjectConfig } from '../../config';
|
|
6
5
|
import type { LikeC4Services } from '../../module';
|
|
7
6
|
import { type IsValidFn } from '../../validation';
|
|
7
|
+
import type { Project } from '../../workspace/ProjectsManager';
|
|
8
8
|
export type GConstructor<T = {}> = new (...args: any[]) => T;
|
|
9
9
|
export declare function toSingleLine(str: string): string;
|
|
10
10
|
export declare function toSingleLine(str: string | undefined | null): string | undefined;
|
|
@@ -23,11 +23,7 @@ export declare class BaseParser {
|
|
|
23
23
|
readonly doc: ParsedLikeC4LangiumDocument;
|
|
24
24
|
isValid: IsValidFn;
|
|
25
25
|
constructor(services: LikeC4Services, doc: ParsedLikeC4LangiumDocument);
|
|
26
|
-
get project():
|
|
27
|
-
id: c4.ProjectId;
|
|
28
|
-
folderUri: URI;
|
|
29
|
-
config: Readonly<ProjectConfig>;
|
|
30
|
-
};
|
|
26
|
+
get project(): Project;
|
|
31
27
|
resolveFqn(node: ast.FqnReferenceable): c4.Fqn;
|
|
32
28
|
getAstNodePath(node: AstNode): any;
|
|
33
29
|
getMetadata(metadataAstNode: ast.MetadataProperty | undefined): {
|
|
@@ -43,6 +39,7 @@ export declare class BaseParser {
|
|
|
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): ParsedElementStyle;
|
|
48
45
|
parseStyleProps(styleProps: Array<ast.StyleProperty> | undefined): ParsedElementStyle;
|
|
@@ -23,6 +23,7 @@ import {
|
|
|
23
23
|
parseMarkdownAsString,
|
|
24
24
|
toColor
|
|
25
25
|
} from "../../ast.js";
|
|
26
|
+
import { logger } from "../../logger.js";
|
|
26
27
|
import { projectIdFrom } from "../../utils/index.js";
|
|
27
28
|
import { readStrictFqn } from "../../utils/elementRef.js";
|
|
28
29
|
import { checksFromDiagnostics } from "../../validation/index.js";
|
|
@@ -179,10 +180,14 @@ export class BaseParser {
|
|
|
179
180
|
}
|
|
180
181
|
case (value && hasProtocol(value)): {
|
|
181
182
|
if (value.startsWith("file:")) {
|
|
183
|
+
logger.warn(`Icon property '${value}' used the 'file' protocol which is not supported`);
|
|
182
184
|
return void 0;
|
|
183
185
|
}
|
|
184
186
|
return value;
|
|
185
187
|
}
|
|
188
|
+
case (value && value.startsWith("@")): {
|
|
189
|
+
return this.parseImageAlias(value);
|
|
190
|
+
}
|
|
186
191
|
case (value && isRelative(value)): {
|
|
187
192
|
return joinRelativeURL(this.doc.uri.toString(), "../", value);
|
|
188
193
|
}
|
|
@@ -190,10 +195,24 @@ export class BaseParser {
|
|
|
190
195
|
return joinURL(this.project.folderUri.toString(), value);
|
|
191
196
|
}
|
|
192
197
|
default: {
|
|
198
|
+
logger.warn(`Icon property '${value}' is not a valid URL, library icon, image alias or 'none'`);
|
|
193
199
|
return void 0;
|
|
194
200
|
}
|
|
195
201
|
}
|
|
196
202
|
}
|
|
203
|
+
parseImageAlias(value) {
|
|
204
|
+
const slashIndex = value.indexOf("/");
|
|
205
|
+
const aliasName = slashIndex > 0 ? value.substring(0, slashIndex) : value;
|
|
206
|
+
const remainingPath = slashIndex > 0 ? value.substring(slashIndex + 1) : "";
|
|
207
|
+
const imageAliases = { "@": "./images", ...this.project.config.imageAliases || {} };
|
|
208
|
+
const aliasPath = imageAliases[aliasName];
|
|
209
|
+
if (!aliasPath) {
|
|
210
|
+
logger.warn(`Image alias "${aliasName}" not found in project configuration`);
|
|
211
|
+
return void 0;
|
|
212
|
+
}
|
|
213
|
+
const fullPath = remainingPath ? joinURL(aliasPath, remainingPath) : aliasPath;
|
|
214
|
+
return joinURL(this.project.folderUri.toString(), fullPath);
|
|
215
|
+
}
|
|
197
216
|
parseColorLiteral(astNode) {
|
|
198
217
|
if (!this.isValid(astNode)) {
|
|
199
218
|
return void 0;
|
|
@@ -30,11 +30,7 @@ export declare function DeploymentModelParser<TBase extends WithExpressionV2>(B:
|
|
|
30
30
|
isValid: import("../../validation").IsValidFn;
|
|
31
31
|
readonly services: import("../..").LikeC4Services;
|
|
32
32
|
readonly doc: import("../../ast").ParsedLikeC4LangiumDocument;
|
|
33
|
-
get project():
|
|
34
|
-
id: c4.ProjectId;
|
|
35
|
-
folderUri: c4;
|
|
36
|
-
config: Readonly<import("../../config").ProjectConfig>;
|
|
37
|
-
};
|
|
33
|
+
get project(): import("../../workspace").Project;
|
|
38
34
|
resolveFqn(node: ast.FqnReferenceable): c4.Fqn;
|
|
39
35
|
getAstNodePath(node: c4): any;
|
|
40
36
|
getMetadata(metadataAstNode: ast.MetadataProperty | undefined): {
|
|
@@ -50,6 +46,7 @@ export declare function DeploymentModelParser<TBase extends WithExpressionV2>(B:
|
|
|
50
46
|
convertLinks(source?: ast.LinkProperty["$container"]): c4.Link[] | undefined;
|
|
51
47
|
parseLinks(source?: ast.LinkProperty["$container"]): c4.Link[] | undefined;
|
|
52
48
|
parseIconProperty(prop: ast.IconProperty | undefined): c4.IconUrl | undefined;
|
|
49
|
+
parseImageAlias(value: string): string | undefined;
|
|
53
50
|
parseColorLiteral(astNode: ast.ColorLiteral): c4.ColorLiteral | undefined;
|
|
54
51
|
parseElementStyle(elementProps: Array<ast.ElementProperty> | ast.ElementStyleProperty | undefined): import("../../ast").ParsedElementStyle;
|
|
55
52
|
parseStyleProps(styleProps: Array<ast.StyleProperty> | undefined): import("../../ast").ParsedElementStyle;
|