@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
|
@@ -0,0 +1,194 @@
|
|
|
1
|
+
import {
|
|
2
|
+
computeColorValues,
|
|
3
|
+
DeploymentElement,
|
|
4
|
+
parentFqn,
|
|
5
|
+
sortByFqnHierarchically
|
|
6
|
+
} from "@likec4/core";
|
|
7
|
+
import { resolveRulesExtendedViews } from "@likec4/core/compute-view";
|
|
8
|
+
import {
|
|
9
|
+
filter,
|
|
10
|
+
flatMap,
|
|
11
|
+
indexBy,
|
|
12
|
+
isDefined,
|
|
13
|
+
isNullish,
|
|
14
|
+
isTruthy,
|
|
15
|
+
map,
|
|
16
|
+
mapValues,
|
|
17
|
+
pipe,
|
|
18
|
+
prop,
|
|
19
|
+
reduce
|
|
20
|
+
} from "remeda";
|
|
21
|
+
import { logger } from "../../logger.js";
|
|
22
|
+
import { resolveRelativePaths } from "../../view-utils/index.js";
|
|
23
|
+
import { MergedExtends } from "./MergedExtends.js";
|
|
24
|
+
import { MergedSpecification } from "./MergedSpecification.js";
|
|
25
|
+
export function buildModel(docs) {
|
|
26
|
+
const c4Specification = new MergedSpecification(docs);
|
|
27
|
+
const customColorDefinitions = mapValues(
|
|
28
|
+
c4Specification.specs.colors,
|
|
29
|
+
(c) => computeColorValues(c.color)
|
|
30
|
+
);
|
|
31
|
+
const elementExtends = new MergedExtends();
|
|
32
|
+
const deploymentExtends = new MergedExtends();
|
|
33
|
+
const elements = pipe(
|
|
34
|
+
docs,
|
|
35
|
+
flatMap((d) => {
|
|
36
|
+
elementExtends.merge(d.c4ExtendElements);
|
|
37
|
+
return map(d.c4Elements, c4Specification.toModelElement);
|
|
38
|
+
}),
|
|
39
|
+
filter(isTruthy),
|
|
40
|
+
// sort from root elements to nested, so that parent is always present
|
|
41
|
+
// Import to preserve the order from the source
|
|
42
|
+
sortByFqnHierarchically,
|
|
43
|
+
reduce(
|
|
44
|
+
(acc, el) => {
|
|
45
|
+
const parent = parentFqn(el.id);
|
|
46
|
+
if (parent && isNullish(acc[parent])) {
|
|
47
|
+
logger.debug`No parent found for ${el.id}`;
|
|
48
|
+
return acc;
|
|
49
|
+
}
|
|
50
|
+
acc[el.id] = elementExtends.apply(el);
|
|
51
|
+
return acc;
|
|
52
|
+
},
|
|
53
|
+
{}
|
|
54
|
+
)
|
|
55
|
+
);
|
|
56
|
+
const relations = pipe(
|
|
57
|
+
docs,
|
|
58
|
+
flatMap((d) => map(d.c4Relations, c4Specification.toModelRelation)),
|
|
59
|
+
filter((rel) => {
|
|
60
|
+
if (!rel) return false;
|
|
61
|
+
if (isNullish(elements[rel.source]) || isNullish(elements[rel.target])) {
|
|
62
|
+
logger.debug`Invalid relation ${rel.id}
|
|
63
|
+
source: ${rel.source} resolved: ${!!elements[rel.source]}
|
|
64
|
+
target: ${rel.target} resolved: ${!!elements[rel.target]}\n`;
|
|
65
|
+
return false;
|
|
66
|
+
}
|
|
67
|
+
return true;
|
|
68
|
+
}),
|
|
69
|
+
indexBy(prop("id"))
|
|
70
|
+
);
|
|
71
|
+
const deploymentElements = pipe(
|
|
72
|
+
docs,
|
|
73
|
+
flatMap((d) => {
|
|
74
|
+
deploymentExtends.merge(d.c4ExtendDeployments);
|
|
75
|
+
return map(d.c4Deployments, c4Specification.toDeploymentElement);
|
|
76
|
+
}),
|
|
77
|
+
filter(isTruthy),
|
|
78
|
+
// sort from root elements to nested, so that parent is always present
|
|
79
|
+
// Import to preserve the order from the source
|
|
80
|
+
sortByFqnHierarchically,
|
|
81
|
+
reduce(
|
|
82
|
+
(acc, el) => {
|
|
83
|
+
const parent = parentFqn(el.id);
|
|
84
|
+
if (parent && isNullish(acc[parent])) {
|
|
85
|
+
logger.debug`No parent found for deployment element ${el.id}`;
|
|
86
|
+
return acc;
|
|
87
|
+
}
|
|
88
|
+
acc[el.id] = DeploymentElement.isDeploymentNode(el) ? deploymentExtends.apply(el) : el;
|
|
89
|
+
return acc;
|
|
90
|
+
},
|
|
91
|
+
{}
|
|
92
|
+
)
|
|
93
|
+
);
|
|
94
|
+
const deploymentRelations = pipe(
|
|
95
|
+
docs,
|
|
96
|
+
flatMap((d) => map(d.c4DeploymentRelations, c4Specification.toDeploymentRelation)),
|
|
97
|
+
filter((rel) => {
|
|
98
|
+
if (!rel) return false;
|
|
99
|
+
if (isNullish(deploymentElements[rel.source.id]) || isNullish(deploymentElements[rel.target.id])) {
|
|
100
|
+
logger.debug`Invalid deployment relation ${rel.id}
|
|
101
|
+
source: ${rel.source.id} resolved: ${!!deploymentElements[rel.source.id]}
|
|
102
|
+
target: ${rel.target.id} resolved: ${!!deploymentElements[rel.target.id]}\n`;
|
|
103
|
+
return false;
|
|
104
|
+
}
|
|
105
|
+
return true;
|
|
106
|
+
}),
|
|
107
|
+
reduce(
|
|
108
|
+
(acc, el) => {
|
|
109
|
+
if (isDefined(acc[el.id])) {
|
|
110
|
+
logger.debug`Duplicate deployment relation ${el.id}`;
|
|
111
|
+
return acc;
|
|
112
|
+
}
|
|
113
|
+
acc[el.id] = el;
|
|
114
|
+
return acc;
|
|
115
|
+
},
|
|
116
|
+
{}
|
|
117
|
+
)
|
|
118
|
+
);
|
|
119
|
+
function toC4View(doc) {
|
|
120
|
+
const docUri = doc.uri.toString();
|
|
121
|
+
return (parsedAstView) => {
|
|
122
|
+
let {
|
|
123
|
+
id,
|
|
124
|
+
title,
|
|
125
|
+
description,
|
|
126
|
+
// ignore this property
|
|
127
|
+
astPath: _ignore,
|
|
128
|
+
// model should include discriminant __
|
|
129
|
+
...model
|
|
130
|
+
} = parsedAstView;
|
|
131
|
+
if (parsedAstView.__ === "element" && isNullish(title) && "viewOf" in parsedAstView) {
|
|
132
|
+
title = elements[parsedAstView.viewOf]?.title ?? null;
|
|
133
|
+
}
|
|
134
|
+
if (isNullish(title) && id === "index") {
|
|
135
|
+
title = "Landscape view";
|
|
136
|
+
}
|
|
137
|
+
return {
|
|
138
|
+
...model,
|
|
139
|
+
customColorDefinitions,
|
|
140
|
+
docUri,
|
|
141
|
+
description,
|
|
142
|
+
title,
|
|
143
|
+
id
|
|
144
|
+
};
|
|
145
|
+
};
|
|
146
|
+
}
|
|
147
|
+
const parsedViews = pipe(
|
|
148
|
+
docs,
|
|
149
|
+
flatMap((d) => map(d.c4Views, toC4View(d))),
|
|
150
|
+
// Resolve relative paths and sort by
|
|
151
|
+
resolveRelativePaths
|
|
152
|
+
);
|
|
153
|
+
if (!parsedViews.some((v) => v.id === "index")) {
|
|
154
|
+
parsedViews.unshift({
|
|
155
|
+
__: "element",
|
|
156
|
+
id: "index",
|
|
157
|
+
title: "Landscape view",
|
|
158
|
+
description: null,
|
|
159
|
+
tags: null,
|
|
160
|
+
links: null,
|
|
161
|
+
customColorDefinitions,
|
|
162
|
+
rules: [
|
|
163
|
+
{
|
|
164
|
+
include: [
|
|
165
|
+
{
|
|
166
|
+
wildcard: true
|
|
167
|
+
}
|
|
168
|
+
]
|
|
169
|
+
}
|
|
170
|
+
]
|
|
171
|
+
});
|
|
172
|
+
}
|
|
173
|
+
const views = pipe(
|
|
174
|
+
parsedViews,
|
|
175
|
+
indexBy(prop("id")),
|
|
176
|
+
resolveRulesExtendedViews
|
|
177
|
+
);
|
|
178
|
+
return {
|
|
179
|
+
specification: {
|
|
180
|
+
tags: Array.from(c4Specification.specs.tags),
|
|
181
|
+
elements: c4Specification.specs.elements,
|
|
182
|
+
relationships: c4Specification.specs.relationships,
|
|
183
|
+
deployments: c4Specification.specs.deployments
|
|
184
|
+
},
|
|
185
|
+
elements,
|
|
186
|
+
relations,
|
|
187
|
+
globals: c4Specification.globals,
|
|
188
|
+
views,
|
|
189
|
+
deployments: {
|
|
190
|
+
elements: deploymentElements,
|
|
191
|
+
relations: deploymentRelations
|
|
192
|
+
}
|
|
193
|
+
};
|
|
194
|
+
}
|
|
@@ -1,61 +1,10 @@
|
|
|
1
|
-
import type
|
|
2
|
-
import type { DocumentCache, LangiumDocuments, Stream } from 'langium';
|
|
3
|
-
import { MultiMap } from 'langium';
|
|
4
|
-
import { type DeploymentAstNodeDescription, type LikeC4LangiumDocument, ast } from '../ast';
|
|
1
|
+
import { type LikeC4LangiumDocument, ast } from '../ast';
|
|
5
2
|
import type { LikeC4Services } from '../module';
|
|
6
3
|
import type { LikeC4NameProvider } from '../references';
|
|
7
|
-
|
|
8
|
-
|
|
4
|
+
import { DocumentFqnIndex, FqnIndex } from './fqn-index';
|
|
5
|
+
export declare class DeploymentsIndex extends FqnIndex<ast.DeploymentElement> {
|
|
6
|
+
protected services: LikeC4Services;
|
|
9
7
|
protected Names: LikeC4NameProvider;
|
|
10
|
-
protected langiumDocuments: LangiumDocuments;
|
|
11
|
-
protected documentCache: DocumentCache<string, DocumentDeploymentsIndex>;
|
|
12
8
|
constructor(services: LikeC4Services);
|
|
13
|
-
|
|
14
|
-
get(document: LikeC4LangiumDocument): DocumentDeploymentsIndex;
|
|
15
|
-
/**
|
|
16
|
-
* Nested elements (nodes/artifacts) of the node
|
|
17
|
-
* @param nodeName Name of the deployment node
|
|
18
|
-
* @returns Stream of artifacts
|
|
19
|
-
*/
|
|
20
|
-
nested(node: ast.DeploymentNode): Stream<DeploymentAstNodeDescription>;
|
|
21
|
-
byFqn(fqnName: string): Stream<DeploymentAstNodeDescription>;
|
|
22
|
-
getFqn(node: ast.DeploymentElement): Fqn;
|
|
23
|
-
createDocumentIndex(document: LikeC4LangiumDocument): DocumentDeploymentsIndex;
|
|
24
|
-
}
|
|
25
|
-
/**
|
|
26
|
-
* Index of deployment elements in the document
|
|
27
|
-
*/
|
|
28
|
-
export declare class DocumentDeploymentsIndex {
|
|
29
|
-
private _rootNodes;
|
|
30
|
-
/**
|
|
31
|
-
* Nested of a deployment node
|
|
32
|
-
*/
|
|
33
|
-
private _nested;
|
|
34
|
-
/**
|
|
35
|
-
* All elements by FQN
|
|
36
|
-
*/
|
|
37
|
-
private _byfqn;
|
|
38
|
-
static readonly EMPTY: DocumentDeploymentsIndex;
|
|
39
|
-
constructor(_rootNodes: Array<DeploymentAstNodeDescription>,
|
|
40
|
-
/**
|
|
41
|
-
* Nested of a deployment node
|
|
42
|
-
*/
|
|
43
|
-
_nested: MultiMap<string, DeploymentAstNodeDescription>,
|
|
44
|
-
/**
|
|
45
|
-
* All elements by FQN
|
|
46
|
-
*/
|
|
47
|
-
_byfqn: MultiMap<string, DeploymentAstNodeDescription>);
|
|
48
|
-
rootNodes(): readonly DeploymentAstNodeDescription[];
|
|
49
|
-
byFqn(fqnName: string): readonly DeploymentAstNodeDescription[];
|
|
50
|
-
/**
|
|
51
|
-
* Returns artifacts of a deployment node
|
|
52
|
-
* @param nodeName Name of the deployment node
|
|
53
|
-
* @returns Stream of artifacts
|
|
54
|
-
*/
|
|
55
|
-
nested(nodeName: string): readonly DeploymentAstNodeDescription[];
|
|
56
|
-
/**
|
|
57
|
-
* Returns all deployment elements in the document,
|
|
58
|
-
* with unique combination "type and name"
|
|
59
|
-
*/
|
|
60
|
-
unique(): readonly DeploymentAstNodeDescription[];
|
|
9
|
+
protected createDocumentIndex(document: LikeC4LangiumDocument): DocumentFqnIndex;
|
|
61
10
|
}
|
|
@@ -1,174 +1,98 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
1
|
+
import { ancestorsFqn, AsFqn } from "@likec4/core";
|
|
2
|
+
import { MultiMap } from "@likec4/core/utils";
|
|
3
|
+
import { isDefined, isTruthy } from "remeda";
|
|
3
4
|
import {
|
|
4
5
|
ast,
|
|
5
|
-
ElementOps
|
|
6
|
-
isLikeC4LangiumDocument
|
|
6
|
+
ElementOps
|
|
7
7
|
} from "../ast.js";
|
|
8
8
|
import { logWarnError } from "../logger.js";
|
|
9
|
-
|
|
9
|
+
import { readStrictFqn } from "../utils/elementRef.js";
|
|
10
|
+
import { DocumentFqnIndex, FqnIndex } from "./fqn-index.js";
|
|
11
|
+
export class DeploymentsIndex extends FqnIndex {
|
|
10
12
|
constructor(services) {
|
|
13
|
+
super(services, "deployments-index");
|
|
11
14
|
this.services = services;
|
|
12
15
|
this.Names = services.references.NameProvider;
|
|
13
|
-
this.langiumDocuments = services.shared.workspace.LangiumDocuments;
|
|
14
|
-
this.documentCache = services.DocumentCache;
|
|
15
16
|
}
|
|
16
17
|
Names;
|
|
17
|
-
langiumDocuments;
|
|
18
|
-
documentCache;
|
|
19
|
-
documents() {
|
|
20
|
-
return this.langiumDocuments.all.filter(
|
|
21
|
-
(d) => isLikeC4LangiumDocument(d) && d.state >= DocumentState.IndexedContent
|
|
22
|
-
);
|
|
23
|
-
}
|
|
24
|
-
get(document) {
|
|
25
|
-
if (document.state < DocumentState.IndexedContent) {
|
|
26
|
-
logWarnError(`Document ${document.uri.path} is not indexed`);
|
|
27
|
-
}
|
|
28
|
-
return this.documentCache.get(document.uri, "DeploymentsIndex", () => this.createDocumentIndex(document));
|
|
29
|
-
}
|
|
30
|
-
/**
|
|
31
|
-
* Nested elements (nodes/artifacts) of the node
|
|
32
|
-
* @param nodeName Name of the deployment node
|
|
33
|
-
* @returns Stream of artifacts
|
|
34
|
-
*/
|
|
35
|
-
nested(node) {
|
|
36
|
-
const fqnName = this.getFqn(node);
|
|
37
|
-
return this.documents().flatMap((doc) => this.get(doc).nested(fqnName));
|
|
38
|
-
}
|
|
39
|
-
byFqn(fqnName) {
|
|
40
|
-
return this.documents().flatMap((doc) => this.get(doc).byFqn(fqnName));
|
|
41
|
-
}
|
|
42
|
-
getFqn(node) {
|
|
43
|
-
let id = ElementOps.readId(node);
|
|
44
|
-
if (isTruthy(id)) {
|
|
45
|
-
return id;
|
|
46
|
-
}
|
|
47
|
-
const fqn = [
|
|
48
|
-
this.Names.getNameStrict(node)
|
|
49
|
-
];
|
|
50
|
-
let _node = node;
|
|
51
|
-
let parentNode;
|
|
52
|
-
while (parentNode = AstUtils.getContainerOfType(_node.$container, ast.isDeploymentNode)) {
|
|
53
|
-
fqn.push(this.Names.getNameStrict(parentNode));
|
|
54
|
-
_node = parentNode;
|
|
55
|
-
}
|
|
56
|
-
id = fqn.reduceRight((acc, cur) => `${acc}.${cur}`);
|
|
57
|
-
ElementOps.writeId(node, id);
|
|
58
|
-
return id;
|
|
59
|
-
}
|
|
60
18
|
createDocumentIndex(document) {
|
|
61
19
|
const rootNodes = document.parseResult.value.deployments.flatMap((m) => m.elements);
|
|
62
20
|
if (rootNodes.length === 0) {
|
|
63
|
-
return
|
|
21
|
+
return DocumentFqnIndex.EMPTY;
|
|
64
22
|
}
|
|
65
|
-
const
|
|
66
|
-
const
|
|
67
|
-
const
|
|
23
|
+
const root = new Array();
|
|
24
|
+
const children = new MultiMap();
|
|
25
|
+
const descendants = new MultiMap();
|
|
26
|
+
const byfqn = new MultiMap();
|
|
68
27
|
const Names = this.Names;
|
|
69
28
|
const Descriptions = this.services.workspace.AstNodeDescriptionProvider;
|
|
70
|
-
const createAndSaveDescription = (
|
|
29
|
+
const createAndSaveDescription = (node, name, fqn) => {
|
|
71
30
|
const desc = {
|
|
72
|
-
...Descriptions.createDescription(
|
|
73
|
-
|
|
31
|
+
...Descriptions.createDescription(node, name, document),
|
|
32
|
+
id: fqn
|
|
74
33
|
};
|
|
75
|
-
ElementOps.writeId(
|
|
76
|
-
|
|
34
|
+
ElementOps.writeId(node, fqn);
|
|
35
|
+
byfqn.set(fqn, desc);
|
|
77
36
|
return desc;
|
|
78
37
|
};
|
|
79
|
-
const traverseNode = (
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
38
|
+
const traverseNode = (node, parentFqn) => {
|
|
39
|
+
let thisFqn;
|
|
40
|
+
if (ast.isExtendDeployment(node)) {
|
|
41
|
+
thisFqn = readStrictFqn(node.deploymentNode);
|
|
42
|
+
} else {
|
|
43
|
+
const name = Names.getName(node);
|
|
44
|
+
if (!isTruthy(name)) {
|
|
45
|
+
return [];
|
|
46
|
+
}
|
|
47
|
+
thisFqn = AsFqn(name, parentFqn);
|
|
48
|
+
const desc = createAndSaveDescription(node, name, thisFqn);
|
|
49
|
+
if (!parentFqn) {
|
|
50
|
+
root.push(desc);
|
|
51
|
+
} else {
|
|
52
|
+
children.set(parentFqn, desc);
|
|
53
|
+
}
|
|
54
|
+
if (ast.isDeployedInstance(node)) {
|
|
55
|
+
return [];
|
|
89
56
|
}
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
57
|
+
}
|
|
58
|
+
let _nested = [];
|
|
59
|
+
if (isDefined(node.body)) {
|
|
60
|
+
for (const child of node.body.elements) {
|
|
61
|
+
if (!ast.isDeploymentRelation(child)) {
|
|
62
|
+
try {
|
|
63
|
+
_nested.push(...traverseNode(child, thisFqn));
|
|
64
|
+
} catch (e) {
|
|
65
|
+
logWarnError(e);
|
|
99
66
|
}
|
|
100
67
|
}
|
|
101
|
-
} catch (e) {
|
|
102
|
-
logWarnError(e);
|
|
103
68
|
}
|
|
104
69
|
}
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
return;
|
|
112
|
-
}
|
|
113
|
-
_nested.add(parentFqn, descs[0]);
|
|
114
|
-
})
|
|
115
|
-
);
|
|
70
|
+
_nested = [
|
|
71
|
+
...children.get(thisFqn) ?? [],
|
|
72
|
+
..._nested
|
|
73
|
+
];
|
|
74
|
+
for (const child of _nested) {
|
|
75
|
+
descendants.set(thisFqn, child);
|
|
116
76
|
}
|
|
117
|
-
|
|
77
|
+
if (ast.isExtendDeployment(node)) {
|
|
78
|
+
for (const ancestor of ancestorsFqn(thisFqn)) {
|
|
79
|
+
for (const child of _nested) {
|
|
80
|
+
descendants.set(ancestor, child);
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
return descendants.get(thisFqn) ?? [];
|
|
118
85
|
};
|
|
119
86
|
for (const node of rootNodes) {
|
|
120
87
|
try {
|
|
121
88
|
if (ast.isDeploymentRelation(node)) {
|
|
122
89
|
continue;
|
|
123
90
|
}
|
|
124
|
-
|
|
125
|
-
if (isTruthy(name)) {
|
|
126
|
-
_root.push(createAndSaveDescription({ node, name, fqn: name }));
|
|
127
|
-
traverseNode(node, name);
|
|
128
|
-
}
|
|
91
|
+
traverseNode(node, null);
|
|
129
92
|
} catch (e) {
|
|
130
93
|
logWarnError(e);
|
|
131
94
|
}
|
|
132
95
|
}
|
|
133
|
-
return new
|
|
134
|
-
}
|
|
135
|
-
}
|
|
136
|
-
export class DocumentDeploymentsIndex {
|
|
137
|
-
constructor(_rootNodes, _nested, _byfqn) {
|
|
138
|
-
this._rootNodes = _rootNodes;
|
|
139
|
-
this._nested = _nested;
|
|
140
|
-
this._byfqn = _byfqn;
|
|
141
|
-
}
|
|
142
|
-
static EMPTY = new DocumentDeploymentsIndex([], new MultiMap(), new MultiMap());
|
|
143
|
-
rootNodes() {
|
|
144
|
-
return this._rootNodes;
|
|
145
|
-
}
|
|
146
|
-
byFqn(fqnName) {
|
|
147
|
-
return this._byfqn.get(fqnName);
|
|
148
|
-
}
|
|
149
|
-
/**
|
|
150
|
-
* Returns artifacts of a deployment node
|
|
151
|
-
* @param nodeName Name of the deployment node
|
|
152
|
-
* @returns Stream of artifacts
|
|
153
|
-
*/
|
|
154
|
-
nested(nodeName) {
|
|
155
|
-
return this._nested.get(nodeName);
|
|
156
|
-
}
|
|
157
|
-
/**
|
|
158
|
-
* Returns all deployment elements in the document,
|
|
159
|
-
* with unique combination "type and name"
|
|
160
|
-
*/
|
|
161
|
-
unique() {
|
|
162
|
-
const result = [];
|
|
163
|
-
pipe(
|
|
164
|
-
[...this._byfqn.values()],
|
|
165
|
-
groupBy(prop("name")),
|
|
166
|
-
forEachObj((descs) => {
|
|
167
|
-
if (descs.length === 1) {
|
|
168
|
-
result.push(descs[0]);
|
|
169
|
-
}
|
|
170
|
-
})
|
|
171
|
-
);
|
|
172
|
-
return result;
|
|
96
|
+
return new DocumentFqnIndex(root, children, descendants, byfqn);
|
|
173
97
|
}
|
|
174
98
|
}
|
|
@@ -1,26 +1,57 @@
|
|
|
1
|
-
import type
|
|
2
|
-
import
|
|
3
|
-
import type
|
|
1
|
+
import { type Fqn } from '@likec4/core/types';
|
|
2
|
+
import { DefaultWeakMap, MultiMap } from '@likec4/core/utils';
|
|
3
|
+
import { type AstNode, type LangiumDocuments, type Stream, WorkspaceCache } from 'langium';
|
|
4
|
+
import { type AstNodeDescriptionWithFqn, type LikeC4LangiumDocument, ast } from '../ast';
|
|
4
5
|
import type { LikeC4Services } from '../module';
|
|
5
6
|
import { ADisposable } from '../utils';
|
|
6
|
-
export
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
el: ast.Element;
|
|
10
|
-
doc: FqnIndexedDocument;
|
|
11
|
-
path: string;
|
|
12
|
-
}
|
|
13
|
-
export declare class FqnIndex extends ADisposable {
|
|
14
|
-
private services;
|
|
7
|
+
export declare class FqnIndex<AstNd extends AstNode = ast.Element> extends ADisposable {
|
|
8
|
+
protected services: LikeC4Services;
|
|
9
|
+
private cachePrefix;
|
|
15
10
|
protected langiumDocuments: LangiumDocuments;
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
11
|
+
protected documentCache: DefaultWeakMap<LikeC4LangiumDocument, DocumentFqnIndex>;
|
|
12
|
+
protected workspaceCache: WorkspaceCache<string, AstNodeDescriptionWithFqn[]>;
|
|
13
|
+
constructor(services: LikeC4Services, cachePrefix?: string);
|
|
14
|
+
private documents;
|
|
15
|
+
get(document: LikeC4LangiumDocument): DocumentFqnIndex;
|
|
16
|
+
getFqn(el: AstNd): Fqn;
|
|
17
|
+
byFqn(fqn: Fqn): Stream<AstNodeDescriptionWithFqn>;
|
|
18
|
+
directChildrenOf(parent: Fqn): Stream<AstNodeDescriptionWithFqn>;
|
|
22
19
|
/**
|
|
23
20
|
* Returns descedant elements with unique names in the scope
|
|
24
21
|
*/
|
|
25
|
-
uniqueDescedants(parent: Fqn): Stream<
|
|
22
|
+
uniqueDescedants(parent: Fqn): Stream<AstNodeDescriptionWithFqn>;
|
|
23
|
+
protected createDocumentIndex(document: LikeC4LangiumDocument): DocumentFqnIndex;
|
|
24
|
+
}
|
|
25
|
+
export declare class DocumentFqnIndex {
|
|
26
|
+
private _rootElements;
|
|
27
|
+
/**
|
|
28
|
+
* direct children of elements
|
|
29
|
+
*/
|
|
30
|
+
private _children;
|
|
31
|
+
/**
|
|
32
|
+
* All descendants of an element (unique by name)
|
|
33
|
+
*/
|
|
34
|
+
private _descendants;
|
|
35
|
+
/**
|
|
36
|
+
* All elements by FQN
|
|
37
|
+
*/
|
|
38
|
+
private _byfqn;
|
|
39
|
+
static readonly EMPTY: DocumentFqnIndex;
|
|
40
|
+
constructor(_rootElements: Array<AstNodeDescriptionWithFqn>,
|
|
41
|
+
/**
|
|
42
|
+
* direct children of elements
|
|
43
|
+
*/
|
|
44
|
+
_children: MultiMap<Fqn, AstNodeDescriptionWithFqn>,
|
|
45
|
+
/**
|
|
46
|
+
* All descendants of an element (unique by name)
|
|
47
|
+
*/
|
|
48
|
+
_descendants: MultiMap<Fqn, AstNodeDescriptionWithFqn>,
|
|
49
|
+
/**
|
|
50
|
+
* All elements by FQN
|
|
51
|
+
*/
|
|
52
|
+
_byfqn: MultiMap<Fqn, AstNodeDescriptionWithFqn>);
|
|
53
|
+
rootElements(): readonly AstNodeDescriptionWithFqn[];
|
|
54
|
+
byFqn(fqn: Fqn): readonly AstNodeDescriptionWithFqn[];
|
|
55
|
+
children(parent: Fqn): readonly AstNodeDescriptionWithFqn[];
|
|
56
|
+
descendants(nodeName: Fqn): readonly AstNodeDescriptionWithFqn[];
|
|
26
57
|
}
|