@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
package/dist/model/fqn-index.js
CHANGED
|
@@ -1,103 +1,190 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
1
|
+
import { invariant, nonNullable } from "@likec4/core";
|
|
2
|
+
import { AsFqn } from "@likec4/core/types";
|
|
3
|
+
import { ancestorsFqn, compareNatural, DefaultWeakMap, sortNaturalByFqn } from "@likec4/core/utils";
|
|
4
|
+
import {
|
|
5
|
+
AstUtils,
|
|
6
|
+
DocumentState,
|
|
7
|
+
MultiMap,
|
|
8
|
+
stream
|
|
9
|
+
} from "langium";
|
|
10
|
+
import { isDefined, isEmpty, isTruthy } from "remeda";
|
|
11
|
+
import {
|
|
12
|
+
ast,
|
|
13
|
+
ElementOps,
|
|
14
|
+
isLikeC4LangiumDocument
|
|
15
|
+
} from "../ast.js";
|
|
16
|
+
import { logWarnError } from "../logger.js";
|
|
5
17
|
import { ADisposable } from "../utils/index.js";
|
|
6
|
-
import {
|
|
18
|
+
import { readStrictFqn } from "../utils/elementRef.js";
|
|
7
19
|
export class FqnIndex extends ADisposable {
|
|
8
20
|
constructor(services) {
|
|
9
21
|
super();
|
|
10
22
|
this.services = services;
|
|
11
23
|
this.langiumDocuments = services.shared.workspace.LangiumDocuments;
|
|
24
|
+
this.documentCache = new DefaultWeakMap((doc) => this.createDocumentIndex(doc));
|
|
12
25
|
this.onDispose(
|
|
13
|
-
services.shared.workspace.DocumentBuilder.
|
|
26
|
+
services.shared.workspace.DocumentBuilder.onDocumentPhase(
|
|
14
27
|
DocumentState.IndexedContent,
|
|
15
|
-
async (
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
delete doc.c4fqnIndex;
|
|
19
|
-
delete doc.c4Elements;
|
|
20
|
-
delete doc.c4Specification;
|
|
21
|
-
delete doc.c4Relations;
|
|
22
|
-
delete doc.c4Deployments;
|
|
23
|
-
delete doc.c4DeploymentRelations;
|
|
24
|
-
delete doc.c4Globals;
|
|
25
|
-
delete doc.c4Views;
|
|
26
|
-
try {
|
|
27
|
-
computeDocumentFqn(doc, services);
|
|
28
|
-
} catch (e) {
|
|
29
|
-
logWarnError(e);
|
|
30
|
-
}
|
|
31
|
-
}
|
|
28
|
+
async (doc, _cancelToken) => {
|
|
29
|
+
if (isLikeC4LangiumDocument(doc)) {
|
|
30
|
+
this.documentCache.set(doc, this.createDocumentIndex(doc));
|
|
32
31
|
}
|
|
33
32
|
return await Promise.resolve();
|
|
34
33
|
}
|
|
35
34
|
)
|
|
36
35
|
);
|
|
37
|
-
logger.debug(`[FqnIndex] Created`);
|
|
38
36
|
}
|
|
39
37
|
langiumDocuments;
|
|
40
|
-
|
|
41
|
-
|
|
38
|
+
documentCache;
|
|
39
|
+
cachePrefix = "fqn-index";
|
|
40
|
+
documents() {
|
|
41
|
+
return this.langiumDocuments.all.filter(
|
|
42
|
+
(d) => isLikeC4LangiumDocument(d) && d.state >= DocumentState.IndexedContent
|
|
43
|
+
);
|
|
42
44
|
}
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
}
|
|
45
|
+
get(document) {
|
|
46
|
+
if (document.state < DocumentState.IndexedContent) {
|
|
47
|
+
logWarnError(`Document ${document.uri.path} is not indexed`);
|
|
48
|
+
}
|
|
49
|
+
return this.documentCache.get(document);
|
|
47
50
|
}
|
|
48
51
|
getFqn(el) {
|
|
49
|
-
|
|
52
|
+
let id = ElementOps.readId(el);
|
|
53
|
+
if (isTruthy(id)) {
|
|
54
|
+
return id;
|
|
55
|
+
}
|
|
56
|
+
const doc = AstUtils.getDocument(el);
|
|
57
|
+
invariant(isLikeC4LangiumDocument(doc));
|
|
58
|
+
this.get(doc);
|
|
59
|
+
return nonNullable(ElementOps.readId(el), "Element fqn must be set, invalid state");
|
|
50
60
|
}
|
|
51
61
|
byFqn(fqn) {
|
|
52
|
-
return this.documents.flatMap((doc) => {
|
|
53
|
-
return
|
|
62
|
+
return this.documents().flatMap((doc) => {
|
|
63
|
+
return this.get(doc).byFqn(fqn);
|
|
54
64
|
});
|
|
55
65
|
}
|
|
56
66
|
directChildrenOf(parent) {
|
|
57
|
-
return stream(
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
67
|
+
return stream(
|
|
68
|
+
this.documents().reduce((map, doc) => {
|
|
69
|
+
this.get(doc).children(parent).forEach((desc) => {
|
|
70
|
+
map.add(desc.name, desc);
|
|
71
|
+
});
|
|
72
|
+
return map;
|
|
73
|
+
}, new MultiMap()).entriesGroupedByKey().flatMap(([_name, descs]) => descs.length === 1 ? descs : []).toArray().sort((a, b) => compareNatural(a.name, b.name))
|
|
74
|
+
);
|
|
64
75
|
}
|
|
65
76
|
/**
|
|
66
77
|
* Returns descedant elements with unique names in the scope
|
|
67
78
|
*/
|
|
68
79
|
uniqueDescedants(parent) {
|
|
69
|
-
|
|
70
|
-
()
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
80
|
+
const { children, descendants } = this.documents().reduce((map, doc) => {
|
|
81
|
+
const docIndex = this.get(doc);
|
|
82
|
+
docIndex.children(parent).forEach((desc) => {
|
|
83
|
+
map.children.add(desc.name, desc);
|
|
84
|
+
});
|
|
85
|
+
docIndex.descendants(parent).forEach((desc) => {
|
|
86
|
+
map.descendants.add(desc.name, desc);
|
|
87
|
+
});
|
|
88
|
+
return map;
|
|
89
|
+
}, {
|
|
90
|
+
children: new MultiMap(),
|
|
91
|
+
descendants: new MultiMap()
|
|
92
|
+
});
|
|
93
|
+
const uniqueChildren = children.entriesGroupedByKey().flatMap(([_name, descs]) => descs.length === 1 ? descs : []).toArray().sort((a, b) => compareNatural(a.name, b.name));
|
|
94
|
+
const uniqueDescendants = descendants.entriesGroupedByKey().flatMap(([_name, descs]) => descs.length === 1 && !children.has(_name) ? descs : []).toArray();
|
|
95
|
+
return stream([
|
|
96
|
+
...uniqueChildren,
|
|
97
|
+
...sortNaturalByFqn(uniqueDescendants)
|
|
98
|
+
]);
|
|
99
|
+
}
|
|
100
|
+
createDocumentIndex(document) {
|
|
101
|
+
const rootElements = document.parseResult.value.models.flatMap((m) => m.elements);
|
|
102
|
+
if (rootElements.length === 0) {
|
|
103
|
+
return DocumentFqnIndex.EMPTY;
|
|
104
|
+
}
|
|
105
|
+
const root = new Array();
|
|
106
|
+
const children = new MultiMap();
|
|
107
|
+
const descendants = new MultiMap();
|
|
108
|
+
const byfqn = new MultiMap();
|
|
109
|
+
const Descriptions = this.services.workspace.AstNodeDescriptionProvider;
|
|
110
|
+
const createAndSaveDescription = (node, name, fqn) => {
|
|
111
|
+
const desc = {
|
|
112
|
+
...Descriptions.createDescription(node, name, document),
|
|
113
|
+
id: fqn
|
|
114
|
+
};
|
|
115
|
+
ElementOps.writeId(node, fqn);
|
|
116
|
+
byfqn.add(fqn, desc);
|
|
117
|
+
return desc;
|
|
118
|
+
};
|
|
119
|
+
const traverseNode = (el, parentFqn) => {
|
|
120
|
+
let thisFqn;
|
|
121
|
+
if (ast.isElement(el)) {
|
|
122
|
+
thisFqn = AsFqn(el.name, parentFqn);
|
|
123
|
+
const desc = createAndSaveDescription(el, el.name, thisFqn);
|
|
124
|
+
if (!parentFqn) {
|
|
125
|
+
root.push(desc);
|
|
126
|
+
} else {
|
|
127
|
+
children.add(parentFqn, desc);
|
|
87
128
|
}
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
129
|
+
} else {
|
|
130
|
+
thisFqn = readStrictFqn(el.element);
|
|
131
|
+
}
|
|
132
|
+
let _nested = [];
|
|
133
|
+
if (isDefined(el.body) && !isEmpty(el.body.elements)) {
|
|
134
|
+
for (const child of el.body.elements) {
|
|
135
|
+
if (!ast.isRelation(child)) {
|
|
136
|
+
try {
|
|
137
|
+
_nested.push(...traverseNode(child, thisFqn));
|
|
138
|
+
} catch (e) {
|
|
139
|
+
logWarnError(e);
|
|
140
|
+
}
|
|
91
141
|
}
|
|
92
142
|
}
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
143
|
+
}
|
|
144
|
+
const directChildren = children.get(thisFqn);
|
|
145
|
+
_nested = [
|
|
146
|
+
...directChildren,
|
|
147
|
+
..._nested
|
|
148
|
+
];
|
|
149
|
+
descendants.addAll(thisFqn, _nested);
|
|
150
|
+
if (ast.isExtendElement(el)) {
|
|
151
|
+
ancestorsFqn(thisFqn).forEach((ancestor) => {
|
|
152
|
+
descendants.addAll(ancestor, _nested);
|
|
153
|
+
});
|
|
154
|
+
}
|
|
155
|
+
return descendants.get(thisFqn);
|
|
156
|
+
};
|
|
157
|
+
for (const node of rootElements) {
|
|
158
|
+
try {
|
|
159
|
+
if (ast.isRelation(node)) {
|
|
160
|
+
continue;
|
|
98
161
|
}
|
|
99
|
-
|
|
162
|
+
traverseNode(node, null);
|
|
163
|
+
} catch (e) {
|
|
164
|
+
logWarnError(e);
|
|
100
165
|
}
|
|
101
|
-
|
|
166
|
+
}
|
|
167
|
+
return new DocumentFqnIndex(root, children, descendants, byfqn);
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
export class DocumentFqnIndex {
|
|
171
|
+
constructor(_rootElements, _children, _descendants, _byfqn) {
|
|
172
|
+
this._rootElements = _rootElements;
|
|
173
|
+
this._children = _children;
|
|
174
|
+
this._descendants = _descendants;
|
|
175
|
+
this._byfqn = _byfqn;
|
|
176
|
+
}
|
|
177
|
+
static EMPTY = new DocumentFqnIndex([], new MultiMap(), new MultiMap(), new MultiMap());
|
|
178
|
+
rootElements() {
|
|
179
|
+
return this._rootElements;
|
|
180
|
+
}
|
|
181
|
+
byFqn(fqn) {
|
|
182
|
+
return this._byfqn.get(fqn);
|
|
183
|
+
}
|
|
184
|
+
children(parent) {
|
|
185
|
+
return this._children.get(parent);
|
|
186
|
+
}
|
|
187
|
+
descendants(nodeName) {
|
|
188
|
+
return this._descendants.get(nodeName);
|
|
102
189
|
}
|
|
103
190
|
}
|
package/dist/model/index.d.ts
CHANGED
package/dist/model/index.js
CHANGED
|
@@ -1,30 +1,34 @@
|
|
|
1
1
|
import type * as c4 from '@likec4/core';
|
|
2
|
-
import { type ViewId } from '@likec4/core';
|
|
3
|
-
import type
|
|
4
|
-
import { Disposable } from 'langium';
|
|
2
|
+
import { type ViewId, LikeC4Model } from '@likec4/core';
|
|
3
|
+
import { type Cancellation, type URI, Disposable } from 'langium';
|
|
5
4
|
import type { LikeC4Services } from '../module';
|
|
6
5
|
import { ADisposable } from '../utils';
|
|
7
6
|
type ModelParsedListener = (docs: URI[]) => void;
|
|
7
|
+
type ParseModelResult = {
|
|
8
|
+
model: c4.ParsedLikeC4Model;
|
|
9
|
+
computeView: (view: c4.LikeC4View) => c4.ComputeViewResult;
|
|
10
|
+
};
|
|
8
11
|
export declare class LikeC4ModelBuilder extends ADisposable {
|
|
9
|
-
private
|
|
10
|
-
private langiumDocuments;
|
|
12
|
+
private parser;
|
|
11
13
|
private listeners;
|
|
14
|
+
private cache;
|
|
15
|
+
private DocumentBuilder;
|
|
12
16
|
constructor(services: LikeC4Services);
|
|
13
17
|
/**
|
|
14
18
|
* WARNING:
|
|
15
19
|
* This method is internal and should to be called only when all documents are known to be parsed.
|
|
16
20
|
* Otherwise, the model may be incomplete.
|
|
17
21
|
*/
|
|
18
|
-
|
|
19
|
-
|
|
22
|
+
private unsafeSyncParseModel;
|
|
23
|
+
parseModel(cancelToken?: Cancellation.CancellationToken): Promise<ParseModelResult | null>;
|
|
20
24
|
private previousViews;
|
|
21
25
|
/**
|
|
22
26
|
* WARNING:
|
|
23
27
|
* This method is internal and should to be called only when all documents are known to be parsed.
|
|
24
28
|
* Otherwise, the model may be incomplete.
|
|
25
29
|
*/
|
|
26
|
-
|
|
27
|
-
|
|
30
|
+
unsafeSyncBuildModel(): LikeC4Model.Computed;
|
|
31
|
+
buildLikeC4Model(cancelToken?: Cancellation.CancellationToken): Promise<LikeC4Model.Computed>;
|
|
28
32
|
computeView(viewId: ViewId, cancelToken?: Cancellation.CancellationToken): Promise<c4.ComputedView | null>;
|
|
29
33
|
onModelParsed(callback: ModelParsedListener): Disposable;
|
|
30
34
|
private documents;
|