@likec4/language-server 1.23.1 → 1.24.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/LikeC4FileSystem.d.ts +1 -0
- package/dist/LikeC4FileSystem.js +7 -0
- package/dist/Rpc.js +10 -7
- package/dist/ast.d.ts +13 -29
- package/dist/ast.js +3 -70
- package/dist/bundled.mjs +2466 -2641
- 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 +7 -4
- package/dist/lsp/CompletionProvider.js +20 -2
- package/dist/lsp/DocumentLinkProvider.d.ts +3 -3
- package/dist/lsp/DocumentLinkProvider.js +14 -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 +6 -56
- package/dist/model/deployments-index.js +59 -137
- package/dist/model/fqn-index.d.ts +47 -17
- package/dist/model/fqn-index.js +155 -68
- package/dist/model/index.d.ts +0 -1
- package/dist/model/index.js +0 -1
- package/dist/model/model-builder.d.ts +13 -9
- package/dist/model/model-builder.js +101 -547
- package/dist/model/model-locator.d.ts +1 -0
- package/dist/model/model-locator.js +7 -9
- package/dist/model/model-parser.d.ts +24 -18
- package/dist/model/model-parser.js +51 -31
- 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 +17 -14
- 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 +6 -7
- 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,11 @@
|
|
|
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 } 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 {
|
|
6
|
+
protected services: LikeC4Services;
|
|
9
7
|
protected Names: LikeC4NameProvider;
|
|
10
|
-
protected
|
|
11
|
-
protected documentCache: DocumentCache<string, DocumentDeploymentsIndex>;
|
|
8
|
+
protected cachePrefix: string;
|
|
12
9
|
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[];
|
|
10
|
+
protected createDocumentIndex(document: LikeC4LangiumDocument): DocumentFqnIndex;
|
|
61
11
|
}
|
|
@@ -1,174 +1,96 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
1
|
+
import { ancestorsFqn, AsFqn } from "@likec4/core";
|
|
2
|
+
import { MultiMap } from "langium";
|
|
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);
|
|
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
|
-
|
|
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
|
-
}
|
|
18
|
+
cachePrefix = "deployments-index";
|
|
60
19
|
createDocumentIndex(document) {
|
|
61
20
|
const rootNodes = document.parseResult.value.deployments.flatMap((m) => m.elements);
|
|
62
21
|
if (rootNodes.length === 0) {
|
|
63
|
-
return
|
|
22
|
+
return DocumentFqnIndex.EMPTY;
|
|
64
23
|
}
|
|
65
|
-
const
|
|
66
|
-
const
|
|
67
|
-
const
|
|
24
|
+
const root = new Array();
|
|
25
|
+
const children = new MultiMap();
|
|
26
|
+
const descendants = new MultiMap();
|
|
27
|
+
const byfqn = new MultiMap();
|
|
68
28
|
const Names = this.Names;
|
|
69
29
|
const Descriptions = this.services.workspace.AstNodeDescriptionProvider;
|
|
70
|
-
const createAndSaveDescription = (
|
|
30
|
+
const createAndSaveDescription = (node, name, fqn) => {
|
|
71
31
|
const desc = {
|
|
72
|
-
...Descriptions.createDescription(
|
|
73
|
-
|
|
32
|
+
...Descriptions.createDescription(node, name, document),
|
|
33
|
+
id: fqn
|
|
74
34
|
};
|
|
75
|
-
ElementOps.writeId(
|
|
76
|
-
|
|
35
|
+
ElementOps.writeId(node, fqn);
|
|
36
|
+
byfqn.add(fqn, desc);
|
|
77
37
|
return desc;
|
|
78
38
|
};
|
|
79
|
-
const traverseNode = (
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
39
|
+
const traverseNode = (node, parentFqn) => {
|
|
40
|
+
let thisFqn;
|
|
41
|
+
if (ast.isExtendDeployment(node)) {
|
|
42
|
+
thisFqn = readStrictFqn(node.deploymentNode);
|
|
43
|
+
} else {
|
|
44
|
+
const name = Names.getName(node);
|
|
45
|
+
if (!isTruthy(name)) {
|
|
46
|
+
return [];
|
|
47
|
+
}
|
|
48
|
+
thisFqn = AsFqn(name, parentFqn);
|
|
49
|
+
const desc = createAndSaveDescription(node, name, thisFqn);
|
|
50
|
+
if (!parentFqn) {
|
|
51
|
+
root.push(desc);
|
|
52
|
+
} else {
|
|
53
|
+
children.add(parentFqn, desc);
|
|
89
54
|
}
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
55
|
+
if (ast.isDeployedInstance(node)) {
|
|
56
|
+
return [];
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
let _nested = [];
|
|
60
|
+
if (isDefined(node.body)) {
|
|
61
|
+
for (const child of node.body.elements) {
|
|
62
|
+
if (!ast.isDeploymentRelation(child)) {
|
|
63
|
+
try {
|
|
64
|
+
_nested.push(...traverseNode(child, thisFqn));
|
|
65
|
+
} catch (e) {
|
|
66
|
+
logWarnError(e);
|
|
99
67
|
}
|
|
100
68
|
}
|
|
101
|
-
} catch (e) {
|
|
102
|
-
logWarnError(e);
|
|
103
69
|
}
|
|
104
70
|
}
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
);
|
|
71
|
+
const directChildren = children.get(thisFqn);
|
|
72
|
+
_nested = [
|
|
73
|
+
...directChildren,
|
|
74
|
+
..._nested
|
|
75
|
+
];
|
|
76
|
+
descendants.addAll(thisFqn, _nested);
|
|
77
|
+
if (ast.isExtendDeployment(node)) {
|
|
78
|
+
ancestorsFqn(thisFqn).forEach((ancestor) => {
|
|
79
|
+
descendants.addAll(ancestor, _nested);
|
|
80
|
+
});
|
|
116
81
|
}
|
|
117
|
-
return
|
|
82
|
+
return descendants.get(thisFqn);
|
|
118
83
|
};
|
|
119
84
|
for (const node of rootNodes) {
|
|
120
85
|
try {
|
|
121
86
|
if (ast.isDeploymentRelation(node)) {
|
|
122
87
|
continue;
|
|
123
88
|
}
|
|
124
|
-
|
|
125
|
-
if (isTruthy(name)) {
|
|
126
|
-
_root.push(createAndSaveDescription({ node, name, fqn: name }));
|
|
127
|
-
traverseNode(node, name);
|
|
128
|
-
}
|
|
89
|
+
traverseNode(node, null);
|
|
129
90
|
} catch (e) {
|
|
130
91
|
logWarnError(e);
|
|
131
92
|
}
|
|
132
93
|
}
|
|
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;
|
|
94
|
+
return new DocumentFqnIndex(root, children, descendants, byfqn);
|
|
173
95
|
}
|
|
174
96
|
}
|
|
@@ -1,26 +1,56 @@
|
|
|
1
|
-
import type
|
|
2
|
-
import
|
|
3
|
-
import type
|
|
1
|
+
import { type Fqn } from '@likec4/core/types';
|
|
2
|
+
import { DefaultWeakMap } from '@likec4/core/utils';
|
|
3
|
+
import { type LangiumDocuments, type Stream, MultiMap } 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 interface FqnIndexEntry {
|
|
7
|
-
fqn: Fqn;
|
|
8
|
-
name: string;
|
|
9
|
-
el: ast.Element;
|
|
10
|
-
doc: FqnIndexedDocument;
|
|
11
|
-
path: string;
|
|
12
|
-
}
|
|
13
7
|
export declare class FqnIndex extends ADisposable {
|
|
14
|
-
|
|
8
|
+
protected services: LikeC4Services;
|
|
15
9
|
protected langiumDocuments: LangiumDocuments;
|
|
10
|
+
protected documentCache: DefaultWeakMap<LikeC4LangiumDocument, DocumentFqnIndex>;
|
|
11
|
+
protected cachePrefix: string;
|
|
16
12
|
constructor(services: LikeC4Services);
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
getFqn(el: ast.Element): Fqn
|
|
20
|
-
byFqn(fqn: Fqn): Stream<
|
|
21
|
-
directChildrenOf(parent: Fqn): Stream<
|
|
13
|
+
private documents;
|
|
14
|
+
get(document: LikeC4LangiumDocument): DocumentFqnIndex;
|
|
15
|
+
getFqn(el: ast.Element | ast.DeploymentElement): Fqn;
|
|
16
|
+
byFqn(fqn: Fqn): Stream<AstNodeDescriptionWithFqn>;
|
|
17
|
+
directChildrenOf(parent: Fqn): Stream<AstNodeDescriptionWithFqn>;
|
|
22
18
|
/**
|
|
23
19
|
* Returns descedant elements with unique names in the scope
|
|
24
20
|
*/
|
|
25
|
-
uniqueDescedants(parent: Fqn): Stream<
|
|
21
|
+
uniqueDescedants(parent: Fqn): Stream<AstNodeDescriptionWithFqn>;
|
|
22
|
+
protected createDocumentIndex(document: LikeC4LangiumDocument): DocumentFqnIndex;
|
|
23
|
+
}
|
|
24
|
+
export declare class DocumentFqnIndex {
|
|
25
|
+
private _rootElements;
|
|
26
|
+
/**
|
|
27
|
+
* direct children of elements
|
|
28
|
+
*/
|
|
29
|
+
private _children;
|
|
30
|
+
/**
|
|
31
|
+
* All descendants of an element (unique by name)
|
|
32
|
+
*/
|
|
33
|
+
private _descendants;
|
|
34
|
+
/**
|
|
35
|
+
* All elements by FQN
|
|
36
|
+
*/
|
|
37
|
+
private _byfqn;
|
|
38
|
+
static readonly EMPTY: DocumentFqnIndex;
|
|
39
|
+
constructor(_rootElements: Array<AstNodeDescriptionWithFqn>,
|
|
40
|
+
/**
|
|
41
|
+
* direct children of elements
|
|
42
|
+
*/
|
|
43
|
+
_children: MultiMap<Fqn, AstNodeDescriptionWithFqn>,
|
|
44
|
+
/**
|
|
45
|
+
* All descendants of an element (unique by name)
|
|
46
|
+
*/
|
|
47
|
+
_descendants: MultiMap<Fqn, AstNodeDescriptionWithFqn>,
|
|
48
|
+
/**
|
|
49
|
+
* All elements by FQN
|
|
50
|
+
*/
|
|
51
|
+
_byfqn: MultiMap<Fqn, AstNodeDescriptionWithFqn>);
|
|
52
|
+
rootElements(): readonly AstNodeDescriptionWithFqn[];
|
|
53
|
+
byFqn(fqn: Fqn): readonly AstNodeDescriptionWithFqn[];
|
|
54
|
+
children(parent: Fqn): readonly AstNodeDescriptionWithFqn[];
|
|
55
|
+
descendants(nodeName: Fqn): readonly AstNodeDescriptionWithFqn[];
|
|
26
56
|
}
|