@likec4/language-server 1.23.1 → 1.24.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/LikeC4FileSystem.d.ts +1 -0
- package/dist/LikeC4FileSystem.js +7 -0
- package/dist/Rpc.js +13 -11
- package/dist/ast.d.ts +13 -29
- package/dist/ast.js +3 -70
- package/dist/bundled.mjs +2441 -2610
- package/dist/generated/ast.d.ts +36 -8
- package/dist/generated/ast.js +44 -2
- package/dist/generated/grammar.js +1 -1
- package/dist/index.d.ts +1 -0
- package/dist/index.js +1 -0
- package/dist/likec4lib.d.ts +2 -0
- package/dist/likec4lib.js +3 -0
- package/dist/lsp/CodeLensProvider.js +10 -6
- package/dist/lsp/CompletionProvider.js +20 -2
- package/dist/lsp/DocumentLinkProvider.d.ts +3 -3
- package/dist/lsp/DocumentLinkProvider.js +5 -5
- package/dist/lsp/DocumentSymbolProvider.d.ts +1 -1
- package/dist/lsp/DocumentSymbolProvider.js +5 -2
- package/dist/lsp/HoverProvider.js +20 -7
- package/dist/lsp/SemanticTokenProvider.js +18 -1
- package/dist/model/builder/MergedExtends.d.ts +12 -0
- package/dist/model/builder/MergedExtends.js +67 -0
- package/dist/model/builder/MergedSpecification.d.ts +29 -0
- package/dist/model/builder/MergedSpecification.js +203 -0
- package/dist/model/builder/buildModel.d.ts +3 -0
- package/dist/model/builder/buildModel.js +194 -0
- package/dist/model/deployments-index.d.ts +5 -56
- package/dist/model/deployments-index.js +61 -137
- package/dist/model/fqn-index.d.ts +50 -19
- package/dist/model/fqn-index.js +176 -69
- package/dist/model/index.d.ts +0 -1
- package/dist/model/index.js +0 -1
- package/dist/model/model-builder.d.ts +10 -9
- package/dist/model/model-builder.js +102 -547
- package/dist/model/model-locator.d.ts +2 -1
- package/dist/model/model-locator.js +7 -9
- package/dist/model/model-parser.d.ts +156 -150
- package/dist/model/model-parser.js +68 -38
- package/dist/model/parser/Base.d.ts +3 -3
- package/dist/model/parser/Base.js +15 -9
- package/dist/model/parser/DeploymentModelParser.d.ts +4 -3
- package/dist/model/parser/DeploymentModelParser.js +54 -3
- package/dist/model/parser/DeploymentViewParser.d.ts +3 -2
- package/dist/model/parser/FqnRefParser.d.ts +2 -2
- package/dist/model/parser/GlobalsParser.d.ts +3 -2
- package/dist/model/parser/ModelParser.d.ts +4 -4
- package/dist/model/parser/ModelParser.js +45 -4
- package/dist/model/parser/PredicatesParser.d.ts +2 -2
- package/dist/model/parser/SpecificationParser.d.ts +2 -2
- package/dist/model/parser/ViewsParser.d.ts +3 -2
- package/dist/module.d.ts +2 -3
- package/dist/module.js +2 -3
- package/dist/references/scope-computation.d.ts +1 -1
- package/dist/references/scope-computation.js +14 -11
- package/dist/references/scope-provider.d.ts +16 -4
- package/dist/references/scope-provider.js +64 -30
- package/dist/test/testServices.d.ts +2 -1
- package/dist/test/testServices.js +23 -20
- package/dist/utils/elementRef.d.ts +1 -1
- package/dist/utils/elementRef.js +3 -3
- package/dist/validation/deployment-checks.d.ts +1 -0
- package/dist/validation/deployment-checks.js +12 -0
- package/dist/validation/index.d.ts +1 -1
- package/dist/validation/index.js +8 -1
- package/dist/views/configurable-layouter.js +3 -3
- package/dist/views/likec4-views.d.ts +1 -0
- package/dist/views/likec4-views.js +11 -11
- package/package.json +12 -13
- package/dist/bundled.d.ts +0 -8
- package/dist/bundled.js +0 -25
- package/dist/model/fqn-computation.d.ts +0 -3
- package/dist/model/fqn-computation.js +0 -72
|
@@ -1,7 +1,10 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
1
|
+
import { DefaultWeakMap } from "@likec4/core/utils";
|
|
2
|
+
import { loggable } from "@likec4/log";
|
|
3
|
+
import { DocumentState } from "langium";
|
|
3
4
|
import { pipe } from "remeda";
|
|
4
|
-
import {
|
|
5
|
+
import { DiagnosticSeverity } from "vscode-languageserver-types";
|
|
6
|
+
import { isLikeC4Builtin } from "../likec4lib.js";
|
|
7
|
+
import { logger as rootLogger } from "../logger.js";
|
|
5
8
|
import { BaseParser } from "./parser/Base.js";
|
|
6
9
|
import { DeploymentModelParser } from "./parser/DeploymentModelParser.js";
|
|
7
10
|
import { DeploymentViewParser } from "./parser/DeploymentViewParser.js";
|
|
@@ -24,53 +27,80 @@ const DocumentParserFromMixins = pipe(
|
|
|
24
27
|
);
|
|
25
28
|
export class DocumentParser extends DocumentParserFromMixins {
|
|
26
29
|
}
|
|
30
|
+
const logger = rootLogger.getChild("ModelParser");
|
|
27
31
|
export class LikeC4ModelParser {
|
|
28
32
|
constructor(services) {
|
|
29
33
|
this.services = services;
|
|
30
|
-
|
|
34
|
+
services.shared.workspace.DocumentBuilder.onDocumentPhase(
|
|
35
|
+
DocumentState.Linked,
|
|
36
|
+
(doc) => {
|
|
37
|
+
try {
|
|
38
|
+
if (!isLikeC4Builtin(doc.uri)) {
|
|
39
|
+
this.cachedParsers.set(doc, this.createParser(doc));
|
|
40
|
+
}
|
|
41
|
+
} catch (e) {
|
|
42
|
+
logger.warn(loggable(e));
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
);
|
|
46
|
+
services.shared.workspace.DocumentBuilder.onDocumentPhase(
|
|
47
|
+
DocumentState.Validated,
|
|
48
|
+
(doc) => {
|
|
49
|
+
if (doc.diagnostics?.some((d) => d.severity === DiagnosticSeverity.Error)) {
|
|
50
|
+
this.cachedParsers.delete(doc);
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
);
|
|
54
|
+
}
|
|
55
|
+
cachedParsers = new DefaultWeakMap((doc) => this.createParser(doc));
|
|
56
|
+
documents() {
|
|
57
|
+
return this.services.shared.workspace.LangiumDocuments.all.map(
|
|
58
|
+
(d) => this.parse(d)
|
|
59
|
+
);
|
|
31
60
|
}
|
|
32
|
-
cachedParsers;
|
|
33
61
|
parse(doc) {
|
|
34
|
-
invariant(isFqnIndexedDocument(doc), `Not a FqnIndexedDocument: ${doc.uri.toString(true)}`);
|
|
35
62
|
try {
|
|
36
|
-
const props = {
|
|
37
|
-
c4Specification: {
|
|
38
|
-
tags: /* @__PURE__ */ new Set(),
|
|
39
|
-
elements: {},
|
|
40
|
-
relationships: {},
|
|
41
|
-
colors: {},
|
|
42
|
-
deployments: {}
|
|
43
|
-
},
|
|
44
|
-
c4Elements: [],
|
|
45
|
-
c4ExtendElements: [],
|
|
46
|
-
c4Relations: [],
|
|
47
|
-
c4Deployments: [],
|
|
48
|
-
c4DeploymentRelations: [],
|
|
49
|
-
c4Globals: {
|
|
50
|
-
predicates: {},
|
|
51
|
-
dynamicPredicates: {},
|
|
52
|
-
styles: {}
|
|
53
|
-
},
|
|
54
|
-
c4Views: []
|
|
55
|
-
};
|
|
56
|
-
doc = Object.assign(doc, props);
|
|
57
63
|
const parser = this.forDocument(doc);
|
|
58
|
-
parser.parseSpecification();
|
|
59
|
-
parser.parseModel();
|
|
60
|
-
parser.parseGlobals();
|
|
61
|
-
parser.parseDeployment();
|
|
62
|
-
parser.parseViews();
|
|
63
64
|
return parser.doc;
|
|
64
65
|
} catch (cause) {
|
|
65
66
|
throw new Error(`Error parsing document ${doc.uri.toString()}`, { cause });
|
|
66
67
|
}
|
|
67
68
|
}
|
|
68
69
|
forDocument(doc) {
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
70
|
+
if (doc.state < DocumentState.Linked) {
|
|
71
|
+
logger.warn(`Document ${doc.uri.toString()} is not linked`);
|
|
72
|
+
}
|
|
73
|
+
return this.cachedParsers.get(doc);
|
|
74
|
+
}
|
|
75
|
+
createParser(doc) {
|
|
76
|
+
const props = {
|
|
77
|
+
c4Specification: {
|
|
78
|
+
tags: /* @__PURE__ */ new Set(),
|
|
79
|
+
elements: {},
|
|
80
|
+
relationships: {},
|
|
81
|
+
colors: {},
|
|
82
|
+
deployments: {}
|
|
83
|
+
},
|
|
84
|
+
c4Elements: [],
|
|
85
|
+
c4ExtendElements: [],
|
|
86
|
+
c4ExtendDeployments: [],
|
|
87
|
+
c4Relations: [],
|
|
88
|
+
c4Deployments: [],
|
|
89
|
+
c4DeploymentRelations: [],
|
|
90
|
+
c4Globals: {
|
|
91
|
+
predicates: {},
|
|
92
|
+
dynamicPredicates: {},
|
|
93
|
+
styles: {}
|
|
94
|
+
},
|
|
95
|
+
c4Views: []
|
|
96
|
+
};
|
|
97
|
+
doc = Object.assign(doc, props);
|
|
98
|
+
const parser = new DocumentParser(this.services, doc);
|
|
99
|
+
parser.parseSpecification();
|
|
100
|
+
parser.parseModel();
|
|
101
|
+
parser.parseGlobals();
|
|
102
|
+
parser.parseDeployment();
|
|
103
|
+
parser.parseViews();
|
|
104
|
+
return parser;
|
|
75
105
|
}
|
|
76
106
|
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type * as c4 from '@likec4/core';
|
|
2
2
|
import type { AstNode } from 'langium';
|
|
3
|
-
import { type ParsedLikeC4LangiumDocument,
|
|
3
|
+
import { type ParsedLikeC4LangiumDocument, ast } from '../../ast';
|
|
4
4
|
import type { LikeC4Services } from '../../module';
|
|
5
5
|
import { type IsValidFn } from '../../validation';
|
|
6
6
|
export type GConstructor<T = {}> = new (...args: any[]) => T;
|
|
@@ -23,6 +23,6 @@ export declare class BaseParser {
|
|
|
23
23
|
parseTags<E extends {
|
|
24
24
|
tags?: ast.Tags;
|
|
25
25
|
}>(withTags?: E): c4.NonEmptyArray<c4.Tag> | null;
|
|
26
|
-
convertLinks(source?: ast.LinkProperty['$container']):
|
|
27
|
-
parseLinks(source?: ast.LinkProperty['$container']):
|
|
26
|
+
convertLinks(source?: ast.LinkProperty['$container']): c4.Link[] | undefined;
|
|
27
|
+
parseLinks(source?: ast.LinkProperty['$container']): c4.Link[] | undefined;
|
|
28
28
|
}
|
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { isNonEmptyArray } from "@likec4/core";
|
|
2
2
|
import { filter, flatMap, fromEntries, isEmpty, isNonNullish, isTruthy, map, pipe, unique } from "remeda";
|
|
3
3
|
import stripIndent from "strip-indent";
|
|
4
4
|
import { ast } from "../../ast.js";
|
|
5
|
-
import {
|
|
5
|
+
import { readStrictFqn } from "../../utils/elementRef.js";
|
|
6
6
|
import { checksFromDiagnostics } from "../../validation/index.js";
|
|
7
7
|
export function toSingleLine(str) {
|
|
8
8
|
return isNonNullish(str) ? removeIndent(str).split("\n").join(" ") : void 0;
|
|
@@ -18,15 +18,16 @@ export class BaseParser {
|
|
|
18
18
|
}
|
|
19
19
|
isValid;
|
|
20
20
|
resolveFqn(node) {
|
|
21
|
+
if (ast.isExtendElement(node)) {
|
|
22
|
+
return readStrictFqn(node.element);
|
|
23
|
+
}
|
|
24
|
+
if (ast.isExtendDeployment(node)) {
|
|
25
|
+
return readStrictFqn(node.deploymentNode);
|
|
26
|
+
}
|
|
21
27
|
if (ast.isDeploymentElement(node)) {
|
|
22
28
|
return this.services.likec4.DeploymentsIndex.getFqn(node);
|
|
23
29
|
}
|
|
24
|
-
|
|
25
|
-
return getFqnElementRef(node.element);
|
|
26
|
-
}
|
|
27
|
-
const fqn = this.services.likec4.FqnIndex.getFqn(node);
|
|
28
|
-
invariant(fqn, `Not indexed element: ${this.getAstNodePath(node)}`);
|
|
29
|
-
return fqn;
|
|
30
|
+
return this.services.likec4.FqnIndex.getFqn(node);
|
|
30
31
|
}
|
|
31
32
|
getAstNodePath(node) {
|
|
32
33
|
return this.services.workspace.AstNodeLocator.getAstNodePath(node);
|
|
@@ -84,7 +85,12 @@ export class BaseParser {
|
|
|
84
85
|
const url = p.value;
|
|
85
86
|
if (isTruthy(url)) {
|
|
86
87
|
const title = isTruthy(p.title) ? toSingleLine(p.title) : void 0;
|
|
87
|
-
|
|
88
|
+
const relative = this.services.lsp.DocumentLinkProvider.relativeLink(this.doc, url);
|
|
89
|
+
return {
|
|
90
|
+
url,
|
|
91
|
+
...title && { title },
|
|
92
|
+
...relative && relative !== url && { relative }
|
|
93
|
+
};
|
|
88
94
|
}
|
|
89
95
|
return [];
|
|
90
96
|
})
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type * as c4 from '@likec4/core';
|
|
2
|
-
import { type ParsedAstDeployment, type ParsedAstDeploymentRelation, ast } from '../../ast';
|
|
2
|
+
import { type ParsedAstDeployment, type ParsedAstDeploymentRelation, type ParsedAstExtend, ast } from '../../ast';
|
|
3
3
|
import type { WithExpressionV2 } from './FqnRefParser';
|
|
4
4
|
export type WithDeploymentModel = ReturnType<typeof DeploymentModelParser>;
|
|
5
5
|
export declare function DeploymentModelParser<TBase extends WithExpressionV2>(B: TBase): {
|
|
@@ -7,6 +7,7 @@ export declare function DeploymentModelParser<TBase extends WithExpressionV2>(B:
|
|
|
7
7
|
parseDeployment(): void;
|
|
8
8
|
parseDeploymentNode(astNode: ast.DeploymentNode): ParsedAstDeployment.Node;
|
|
9
9
|
parseDeployedInstance(astNode: ast.DeployedInstance): ParsedAstDeployment.Instance;
|
|
10
|
+
parseExtendDeployment(astNode: ast.ExtendDeployment): ParsedAstExtend | null;
|
|
10
11
|
parseDeploymentRelation(astNode: ast.DeploymentRelation): ParsedAstDeploymentRelation;
|
|
11
12
|
parseFqnRef(astNode: ast.FqnRef): c4.FqnRef;
|
|
12
13
|
parseFqnExpr(astNode: ast.FqnExpr): c4.FqnExpr;
|
|
@@ -29,7 +30,7 @@ export declare function DeploymentModelParser<TBase extends WithExpressionV2>(B:
|
|
|
29
30
|
parseTags<E extends {
|
|
30
31
|
tags?: ast.Tags;
|
|
31
32
|
}>(withTags?: E): c4.NonEmptyArray<c4.Tag> | null;
|
|
32
|
-
convertLinks(source?: ast.LinkProperty["$container"]):
|
|
33
|
-
parseLinks(source?: ast.LinkProperty["$container"]):
|
|
33
|
+
convertLinks(source?: ast.LinkProperty["$container"]): c4.Link[] | undefined;
|
|
34
|
+
parseLinks(source?: ast.LinkProperty["$container"]): c4.Link[] | undefined;
|
|
34
35
|
};
|
|
35
36
|
} & TBase;
|
|
@@ -1,8 +1,7 @@
|
|
|
1
|
-
import { FqnRef, isNonEmptyArray, nameFromFqn, nonexhaustive, nonNullable } from "@likec4/core";
|
|
2
|
-
import { filter, first, isTruthy, map, mapToObj, pipe } from "remeda";
|
|
1
|
+
import { FqnRef, isNonEmptyArray, LinkedList, nameFromFqn, nonexhaustive, nonNullable } from "@likec4/core";
|
|
2
|
+
import { filter, first, isEmpty, isTruthy, map, mapToObj, pipe } from "remeda";
|
|
3
3
|
import {
|
|
4
4
|
ast,
|
|
5
|
-
streamDeploymentModel,
|
|
6
5
|
toElementStyle,
|
|
7
6
|
toRelationshipStyleExcludeDefaults
|
|
8
7
|
} from "../../ast.js";
|
|
@@ -10,6 +9,31 @@ import { logWarnError } from "../../logger.js";
|
|
|
10
9
|
import { elementRef } from "../../utils/elementRef.js";
|
|
11
10
|
import { stringHash } from "../../utils/stringHash.js";
|
|
12
11
|
import { removeIndent, toSingleLine } from "./Base.js";
|
|
12
|
+
function* streamDeploymentModel(doc) {
|
|
13
|
+
const traverseStack = LinkedList.from(
|
|
14
|
+
doc.parseResult.value.deployments.flatMap((m) => m.elements)
|
|
15
|
+
);
|
|
16
|
+
const relations = [];
|
|
17
|
+
let el;
|
|
18
|
+
while (el = traverseStack.shift()) {
|
|
19
|
+
if (ast.isDeploymentRelation(el)) {
|
|
20
|
+
relations.push(el);
|
|
21
|
+
continue;
|
|
22
|
+
}
|
|
23
|
+
if (ast.isDeployedInstance(el)) {
|
|
24
|
+
yield el;
|
|
25
|
+
continue;
|
|
26
|
+
}
|
|
27
|
+
if (el.body && el.body.elements.length > 0) {
|
|
28
|
+
for (const child of el.body.elements) {
|
|
29
|
+
traverseStack.push(child);
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
yield el;
|
|
33
|
+
}
|
|
34
|
+
yield* relations;
|
|
35
|
+
return;
|
|
36
|
+
}
|
|
13
37
|
export function DeploymentModelParser(B) {
|
|
14
38
|
return class DeploymentModelParser extends B {
|
|
15
39
|
parseDeployment() {
|
|
@@ -30,6 +54,13 @@ export function DeploymentModelParser(B) {
|
|
|
30
54
|
doc.c4Deployments.push(this.parseDeploymentNode(el));
|
|
31
55
|
break;
|
|
32
56
|
}
|
|
57
|
+
case ast.isExtendDeployment(el): {
|
|
58
|
+
const parsed = this.parseExtendDeployment(el);
|
|
59
|
+
if (parsed) {
|
|
60
|
+
doc.c4ExtendDeployments.push(parsed);
|
|
61
|
+
}
|
|
62
|
+
break;
|
|
63
|
+
}
|
|
33
64
|
default:
|
|
34
65
|
nonexhaustive(el);
|
|
35
66
|
}
|
|
@@ -112,6 +143,26 @@ export function DeploymentModelParser(B) {
|
|
|
112
143
|
style
|
|
113
144
|
};
|
|
114
145
|
}
|
|
146
|
+
parseExtendDeployment(astNode) {
|
|
147
|
+
if (!this.isValid(astNode)) {
|
|
148
|
+
return null;
|
|
149
|
+
}
|
|
150
|
+
const id = this.resolveFqn(astNode);
|
|
151
|
+
const tags = this.parseTags(astNode.body);
|
|
152
|
+
const metadata = this.getMetadata(astNode.body?.props.find(ast.isMetadataProperty));
|
|
153
|
+
const astPath = this.getAstNodePath(astNode);
|
|
154
|
+
const links = this.parseLinks(astNode.body) ?? [];
|
|
155
|
+
if (!tags && isEmpty(metadata ?? {}) && isEmpty(links)) {
|
|
156
|
+
return null;
|
|
157
|
+
}
|
|
158
|
+
return {
|
|
159
|
+
id,
|
|
160
|
+
astPath,
|
|
161
|
+
...metadata && { metadata },
|
|
162
|
+
...tags && { tags },
|
|
163
|
+
...links && isNonEmptyArray(links) && { links }
|
|
164
|
+
};
|
|
165
|
+
}
|
|
115
166
|
parseDeploymentRelation(astNode) {
|
|
116
167
|
const isValid = this.isValid;
|
|
117
168
|
const astPath = this.getAstNodePath(astNode);
|
|
@@ -30,11 +30,12 @@ export declare function DeploymentViewParser<TBase extends WithExpressionV2 & Wi
|
|
|
30
30
|
parseTags<E extends {
|
|
31
31
|
tags?: ast.Tags;
|
|
32
32
|
}>(withTags?: E): c4.NonEmptyArray<c4.Tag> | null;
|
|
33
|
-
convertLinks(source?: ast.LinkProperty["$container"]):
|
|
34
|
-
parseLinks(source?: ast.LinkProperty["$container"]):
|
|
33
|
+
convertLinks(source?: ast.LinkProperty["$container"]): c4.Link[] | undefined;
|
|
34
|
+
parseLinks(source?: ast.LinkProperty["$container"]): c4.Link[] | undefined;
|
|
35
35
|
parseDeployment(): void;
|
|
36
36
|
parseDeploymentNode(astNode: ast.DeploymentNode): import("../../ast").ParsedAstDeployment.Node;
|
|
37
37
|
parseDeployedInstance(astNode: ast.DeployedInstance): import("../../ast").ParsedAstDeployment.Instance;
|
|
38
|
+
parseExtendDeployment(astNode: ast.ExtendDeployment): import("../../ast").ParsedAstExtend | null;
|
|
38
39
|
parseDeploymentRelation(astNode: ast.DeploymentRelation): import("../../ast").ParsedAstDeploymentRelation;
|
|
39
40
|
};
|
|
40
41
|
} & TBase;
|
|
@@ -25,7 +25,7 @@ export declare function ExpressionV2Parser<TBase extends Base>(B: TBase): {
|
|
|
25
25
|
parseTags<E extends {
|
|
26
26
|
tags?: ast.Tags;
|
|
27
27
|
}>(withTags?: E): c4.NonEmptyArray<c4.Tag> | null;
|
|
28
|
-
convertLinks(source?: ast.LinkProperty["$container"]):
|
|
29
|
-
parseLinks(source?: ast.LinkProperty["$container"]):
|
|
28
|
+
convertLinks(source?: ast.LinkProperty["$container"]): c4.Link[] | undefined;
|
|
29
|
+
parseLinks(source?: ast.LinkProperty["$container"]): c4.Link[] | undefined;
|
|
30
30
|
};
|
|
31
31
|
} & TBase;
|
|
@@ -47,8 +47,8 @@ export declare function GlobalsParser<TBase extends WithViewsParser>(B: TBase):
|
|
|
47
47
|
parseTags<E extends {
|
|
48
48
|
tags?: ast.Tags;
|
|
49
49
|
}>(withTags?: E): c4.NonEmptyArray<c4.Tag> | null;
|
|
50
|
-
convertLinks(source?: ast.LinkProperty["$container"]):
|
|
51
|
-
parseLinks(source?: ast.LinkProperty["$container"]):
|
|
50
|
+
convertLinks(source?: ast.LinkProperty["$container"]): c4.Link[] | undefined;
|
|
51
|
+
parseLinks(source?: ast.LinkProperty["$container"]): c4.Link[] | undefined;
|
|
52
52
|
parseDeploymentView(astNode: ast.DeploymentView): import("../../ast").ParsedAstDeploymentView;
|
|
53
53
|
parseDeploymentViewRule(astRule: ast.DeploymentViewRule): c4.DeploymentViewRule;
|
|
54
54
|
parseDeploymentViewRulePredicate(astRule: ast.DeploymentViewRulePredicate): c4.DeploymentViewRulePredicate;
|
|
@@ -63,6 +63,7 @@ export declare function GlobalsParser<TBase extends WithViewsParser>(B: TBase):
|
|
|
63
63
|
parseDeployment(): void;
|
|
64
64
|
parseDeploymentNode(astNode: ast.DeploymentNode): import("../../ast").ParsedAstDeployment.Node;
|
|
65
65
|
parseDeployedInstance(astNode: ast.DeployedInstance): import("../../ast").ParsedAstDeployment.Instance;
|
|
66
|
+
parseExtendDeployment(astNode: ast.ExtendDeployment): import("../../ast").ParsedAstExtend | null;
|
|
66
67
|
parseDeploymentRelation(astNode: ast.DeploymentRelation): import("../../ast").ParsedAstDeploymentRelation;
|
|
67
68
|
};
|
|
68
69
|
} & TBase;
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
import type * as c4 from '@likec4/core';
|
|
2
|
-
import { type ParsedAstElement, type
|
|
2
|
+
import { type ParsedAstElement, type ParsedAstExtend, type ParsedAstRelation, ast } from '../../ast';
|
|
3
3
|
import { type Base } from './Base';
|
|
4
4
|
export type WithModel = ReturnType<typeof ModelParser>;
|
|
5
5
|
export declare function ModelParser<TBase extends Base>(B: TBase): {
|
|
6
6
|
new (...args: any[]): {
|
|
7
7
|
parseModel(): void;
|
|
8
8
|
parseElement(astNode: ast.Element): ParsedAstElement;
|
|
9
|
-
parseExtendElement(astNode: ast.ExtendElement):
|
|
9
|
+
parseExtendElement(astNode: ast.ExtendElement): ParsedAstExtend | null;
|
|
10
10
|
parseRelation(astNode: ast.Relation): ParsedAstRelation;
|
|
11
11
|
isValid: import("../../validation").IsValidFn;
|
|
12
12
|
readonly services: import("../..").LikeC4Services;
|
|
@@ -22,7 +22,7 @@ export declare function ModelParser<TBase extends Base>(B: TBase): {
|
|
|
22
22
|
parseTags<E extends {
|
|
23
23
|
tags?: ast.Tags;
|
|
24
24
|
}>(withTags?: E): c4.NonEmptyArray<c4.Tag> | null;
|
|
25
|
-
convertLinks(source?: ast.LinkProperty["$container"]):
|
|
26
|
-
parseLinks(source?: ast.LinkProperty["$container"]):
|
|
25
|
+
convertLinks(source?: ast.LinkProperty["$container"]): c4.Link[] | undefined;
|
|
26
|
+
parseLinks(source?: ast.LinkProperty["$container"]): c4.Link[] | undefined;
|
|
27
27
|
};
|
|
28
28
|
} & TBase;
|
|
@@ -1,15 +1,56 @@
|
|
|
1
|
-
import { isNonEmptyArray, nonexhaustive, nonNullable } from "@likec4/core";
|
|
2
|
-
import { filter, first, isEmpty, isNonNullish, isTruthy, map, mapToObj, pipe } from "remeda";
|
|
1
|
+
import { isNonEmptyArray, LinkedList, nonexhaustive, nonNullable } from "@likec4/core";
|
|
2
|
+
import { filter, first, isDefined, isEmpty, isNonNullish, isTruthy, map, mapToObj, pipe } from "remeda";
|
|
3
3
|
import {
|
|
4
4
|
ast,
|
|
5
|
-
resolveRelationPoints,
|
|
6
|
-
streamModel,
|
|
7
5
|
toElementStyle,
|
|
8
6
|
toRelationshipStyleExcludeDefaults
|
|
9
7
|
} from "../../ast.js";
|
|
10
8
|
import { logWarnError } from "../../logger.js";
|
|
9
|
+
import { elementRef } from "../../utils/elementRef.js";
|
|
11
10
|
import { stringHash } from "../../utils/stringHash.js";
|
|
12
11
|
import { removeIndent, toSingleLine } from "./Base.js";
|
|
12
|
+
function resolveRelationPoints(node) {
|
|
13
|
+
const target = elementRef(node.target);
|
|
14
|
+
if (!target) {
|
|
15
|
+
throw new Error("RelationRefError: Invalid reference to target");
|
|
16
|
+
}
|
|
17
|
+
if (isDefined(node.source)) {
|
|
18
|
+
const source = elementRef(node.source);
|
|
19
|
+
if (!source) {
|
|
20
|
+
throw new Error("RelationRefError: Invalid reference to source");
|
|
21
|
+
}
|
|
22
|
+
return {
|
|
23
|
+
source,
|
|
24
|
+
target
|
|
25
|
+
};
|
|
26
|
+
}
|
|
27
|
+
if (!ast.isElementBody(node.$container)) {
|
|
28
|
+
throw new Error("RelationRefError: Invalid container for sourceless relation");
|
|
29
|
+
}
|
|
30
|
+
return {
|
|
31
|
+
source: node.$container.$container,
|
|
32
|
+
target
|
|
33
|
+
};
|
|
34
|
+
}
|
|
35
|
+
function* streamModel(doc) {
|
|
36
|
+
const traverseStack = LinkedList.from(doc.parseResult.value.models.flatMap((m) => m.elements));
|
|
37
|
+
const relations = [];
|
|
38
|
+
let el;
|
|
39
|
+
while (el = traverseStack.shift()) {
|
|
40
|
+
if (ast.isRelation(el)) {
|
|
41
|
+
relations.push(el);
|
|
42
|
+
continue;
|
|
43
|
+
}
|
|
44
|
+
if (el.body && el.body.elements && el.body.elements.length > 0) {
|
|
45
|
+
for (const child of el.body.elements) {
|
|
46
|
+
traverseStack.push(child);
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
yield el;
|
|
50
|
+
}
|
|
51
|
+
yield* relations;
|
|
52
|
+
return;
|
|
53
|
+
}
|
|
13
54
|
export function ModelParser(B) {
|
|
14
55
|
return class ModelParser extends B {
|
|
15
56
|
parseModel() {
|
|
@@ -28,7 +28,7 @@ export declare function PredicatesParser<TBase extends Base>(B: TBase): {
|
|
|
28
28
|
parseTags<E extends {
|
|
29
29
|
tags?: ast.Tags;
|
|
30
30
|
}>(withTags?: E): c4.NonEmptyArray<c4.Tag> | null;
|
|
31
|
-
convertLinks(source?: ast.LinkProperty["$container"]):
|
|
32
|
-
parseLinks(source?: ast.LinkProperty["$container"]):
|
|
31
|
+
convertLinks(source?: ast.LinkProperty["$container"]): c4.Link[] | undefined;
|
|
32
|
+
parseLinks(source?: ast.LinkProperty["$container"]): c4.Link[] | undefined;
|
|
33
33
|
};
|
|
34
34
|
} & TBase;
|
|
@@ -21,7 +21,7 @@ export declare function SpecificationParser<TBase extends Base>(B: TBase): {
|
|
|
21
21
|
parseTags<E extends {
|
|
22
22
|
tags?: ast.Tags;
|
|
23
23
|
}>(withTags?: E): c4.NonEmptyArray<c4.Tag> | null;
|
|
24
|
-
convertLinks(source?: ast.LinkProperty["$container"]):
|
|
25
|
-
parseLinks(source?: ast.LinkProperty["$container"]):
|
|
24
|
+
convertLinks(source?: ast.LinkProperty["$container"]): c4.Link[] | undefined;
|
|
25
|
+
parseLinks(source?: ast.LinkProperty["$container"]): c4.Link[] | undefined;
|
|
26
26
|
};
|
|
27
27
|
} & TBase;
|
|
@@ -45,8 +45,8 @@ export declare function ViewsParser<TBase extends WithPredicates & WithDeploymen
|
|
|
45
45
|
parseTags<E extends {
|
|
46
46
|
tags?: ast.Tags;
|
|
47
47
|
}>(withTags?: E): c4.NonEmptyArray<c4.Tag> | null;
|
|
48
|
-
convertLinks(source?: ast.LinkProperty["$container"]):
|
|
49
|
-
parseLinks(source?: ast.LinkProperty["$container"]):
|
|
48
|
+
convertLinks(source?: ast.LinkProperty["$container"]): c4.Link[] | undefined;
|
|
49
|
+
parseLinks(source?: ast.LinkProperty["$container"]): c4.Link[] | undefined;
|
|
50
50
|
parseDeploymentView(astNode: ast.DeploymentView): import("../../ast").ParsedAstDeploymentView;
|
|
51
51
|
parseDeploymentViewRule(astRule: ast.DeploymentViewRule): c4.DeploymentViewRule;
|
|
52
52
|
parseDeploymentViewRulePredicate(astRule: ast.DeploymentViewRulePredicate): c4.DeploymentViewRulePredicate;
|
|
@@ -61,6 +61,7 @@ export declare function ViewsParser<TBase extends WithPredicates & WithDeploymen
|
|
|
61
61
|
parseDeployment(): void;
|
|
62
62
|
parseDeploymentNode(astNode: ast.DeploymentNode): import("../../ast").ParsedAstDeployment.Node;
|
|
63
63
|
parseDeployedInstance(astNode: ast.DeployedInstance): import("../../ast").ParsedAstDeployment.Instance;
|
|
64
|
+
parseExtendDeployment(astNode: ast.ExtendDeployment): import("../../ast").ParsedAstExtend | null;
|
|
64
65
|
parseDeploymentRelation(astNode: ast.DeploymentRelation): import("../../ast").ParsedAstDeploymentRelation;
|
|
65
66
|
};
|
|
66
67
|
} & TBase;
|
package/dist/module.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { GraphvizLayouter } from '@likec4/layouts';
|
|
2
|
-
import { type Module,
|
|
2
|
+
import { type Module, WorkspaceCache } from 'langium';
|
|
3
3
|
import { type DefaultSharedModuleContext, type LangiumServices, type LangiumSharedServices, type PartialLangiumServices } from 'langium/lsp';
|
|
4
4
|
import { LikeC4DocumentationProvider } from './documentation';
|
|
5
5
|
import { LikeC4CodeLensProvider, LikeC4CompletionProvider, LikeC4DocumentHighlightProvider, LikeC4DocumentLinkProvider, LikeC4DocumentSymbolProvider, LikeC4HoverProvider, LikeC4SemanticTokenProvider } from './lsp';
|
|
@@ -26,8 +26,7 @@ export interface LikeC4AddedServices {
|
|
|
26
26
|
documentation: {
|
|
27
27
|
DocumentationProvider: LikeC4DocumentationProvider;
|
|
28
28
|
};
|
|
29
|
-
|
|
30
|
-
DocumentCache: DocumentCache<string, any>;
|
|
29
|
+
ValidatedWorkspaceCache: WorkspaceCache<string, any>;
|
|
31
30
|
Rpc: Rpc;
|
|
32
31
|
likec4: {
|
|
33
32
|
Views: LikeC4Views;
|
package/dist/module.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { GraphvizLayouter, GraphvizWasmAdapter } from "@likec4/layouts";
|
|
2
2
|
import {
|
|
3
|
-
|
|
3
|
+
DocumentState,
|
|
4
4
|
EmptyFileSystem,
|
|
5
5
|
inject,
|
|
6
6
|
WorkspaceCache
|
|
@@ -62,8 +62,7 @@ export const LikeC4Module = {
|
|
|
62
62
|
documentation: {
|
|
63
63
|
DocumentationProvider: bind(LikeC4DocumentationProvider)
|
|
64
64
|
},
|
|
65
|
-
|
|
66
|
-
DocumentCache: (services) => new DocumentCache(services.shared),
|
|
65
|
+
ValidatedWorkspaceCache: (services) => new WorkspaceCache(services.shared, DocumentState.Validated),
|
|
67
66
|
Rpc: bind(Rpc),
|
|
68
67
|
likec4: {
|
|
69
68
|
Layouter: (_services) => {
|
|
@@ -3,7 +3,7 @@ import type { CancellationToken } from 'vscode-languageserver';
|
|
|
3
3
|
import { type LikeC4LangiumDocument, ast } from '../ast';
|
|
4
4
|
import type { LikeC4Services } from '../module';
|
|
5
5
|
type ElementsContainer = ast.Model | ast.ElementBody | ast.ExtendElementBody;
|
|
6
|
-
type DeploymentsContainer = ast.ModelDeployments | ast.DeploymentNodeBody;
|
|
6
|
+
type DeploymentsContainer = ast.ModelDeployments | ast.DeploymentNodeBody | ast.ExtendDeploymentBody;
|
|
7
7
|
export declare class LikeC4ScopeComputation extends DefaultScopeComputation {
|
|
8
8
|
constructor(services: LikeC4Services);
|
|
9
9
|
computeExports(document: LikeC4LangiumDocument, _cancelToken?: CancellationToken): Promise<AstNodeDescription[]>;
|
|
@@ -242,19 +242,20 @@ export class LikeC4ScopeComputation extends DefaultScopeComputation {
|
|
|
242
242
|
return local;
|
|
243
243
|
}
|
|
244
244
|
processDeployments(container, scopes, document) {
|
|
245
|
-
const
|
|
245
|
+
const localScope = new MultiMap();
|
|
246
246
|
const descedants = [];
|
|
247
247
|
for (const el of container.elements) {
|
|
248
248
|
if (ast.isDeploymentRelation(el)) {
|
|
249
249
|
continue;
|
|
250
250
|
}
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
251
|
+
if (!ast.isExtendDeployment(el)) {
|
|
252
|
+
let name = this.nameProvider.getName(el);
|
|
253
|
+
if (isTruthy(name)) {
|
|
254
|
+
const desc = this.descriptions.createDescription(el, name, document);
|
|
255
|
+
localScope.add(name, desc);
|
|
256
|
+
}
|
|
256
257
|
}
|
|
257
|
-
if (ast.
|
|
258
|
+
if (!ast.isDeployedInstance(el) && el.body) {
|
|
258
259
|
try {
|
|
259
260
|
descedants.push(
|
|
260
261
|
...this.processDeployments(el.body, scopes, document)
|
|
@@ -264,18 +265,20 @@ export class LikeC4ScopeComputation extends DefaultScopeComputation {
|
|
|
264
265
|
}
|
|
265
266
|
}
|
|
266
267
|
}
|
|
267
|
-
if (descedants.length
|
|
268
|
+
if (descedants.length) {
|
|
268
269
|
pipe(
|
|
269
270
|
descedants,
|
|
270
|
-
filter((desc) => !
|
|
271
|
+
filter((desc) => !localScope.has(desc.name)),
|
|
271
272
|
groupBy((desc) => desc.name),
|
|
272
273
|
forEachObj((descs, name) => {
|
|
273
274
|
if (descs.length === 1) {
|
|
274
|
-
|
|
275
|
+
localScope.add(name, descs[0]);
|
|
275
276
|
}
|
|
276
277
|
})
|
|
277
278
|
);
|
|
278
279
|
}
|
|
279
|
-
|
|
280
|
+
const local = [...localScope.values()];
|
|
281
|
+
scopes.addAll(container, local);
|
|
282
|
+
return local;
|
|
280
283
|
}
|
|
281
284
|
}
|
|
@@ -5,12 +5,24 @@ export declare class LikeC4ScopeProvider extends DefaultScopeProvider {
|
|
|
5
5
|
private deploymentsIndex;
|
|
6
6
|
private fqnIndex;
|
|
7
7
|
constructor(services: LikeC4Services);
|
|
8
|
-
private directChildrenOf;
|
|
9
8
|
private uniqueDescedants;
|
|
10
|
-
private scopeElementRef;
|
|
11
|
-
private scopeExtendElement;
|
|
12
|
-
private scopeElementView;
|
|
13
9
|
getScope(context: ReferenceInfo): Scope;
|
|
10
|
+
private getScopeElementRef;
|
|
11
|
+
private getScopeExtendElement;
|
|
12
|
+
private getScopeElementView;
|
|
13
|
+
private getScopeForStrictFqnRef;
|
|
14
|
+
private getScopeExtendDeployment;
|
|
14
15
|
protected getScopeForFqnRef(container: ast.FqnRef, context: ReferenceInfo): any;
|
|
16
|
+
/**
|
|
17
|
+
* Computes the scope for a given reference context.
|
|
18
|
+
*
|
|
19
|
+
* @param context - The reference information containing the context for which the scope is being computed.
|
|
20
|
+
* @param referenceType - The type of reference being resolved. Defaults to the reference type derived from the context.
|
|
21
|
+
* @returns A scope containing the relevant AST node descriptions for the given reference context.
|
|
22
|
+
*
|
|
23
|
+
* This method first checks if there are precomputed scopes available in the document. If not, it falls back to the global scope.
|
|
24
|
+
* It then iterates through the container hierarchy, collecting relevant scopes based on the reference type and container type.
|
|
25
|
+
* Finally, it combines the collected scopes with the global scope to produce the final scope.
|
|
26
|
+
*/
|
|
15
27
|
protected computeScope(context: ReferenceInfo, referenceType?: any): any;
|
|
16
28
|
}
|