@likec4/language-server 0.37.0 → 0.40.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/Rpc.d.ts +6 -0
- package/dist/Rpc.js +130 -0
- package/dist/ast.d.ts +0 -97
- package/dist/ast.js +127 -143
- package/dist/elementRef.d.ts +1 -2
- package/dist/elementRef.js +31 -44
- package/dist/generated/ast.d.ts +4 -5
- package/dist/generated/ast.js +310 -315
- package/dist/generated/grammar.d.ts +0 -2
- package/dist/generated/grammar.js +2 -3177
- package/dist/generated/module.d.ts +1 -6
- package/dist/generated/module.js +13 -18
- package/dist/index.d.ts +0 -1
- package/dist/index.js +2 -3
- package/dist/logger.d.ts +0 -1
- package/dist/logger.js +39 -42
- package/dist/lsp/CodeLensProvider.d.ts +0 -1
- package/dist/lsp/CodeLensProvider.js +28 -32
- package/dist/lsp/DocumentLinkProvider.d.ts +0 -1
- package/dist/lsp/DocumentLinkProvider.js +26 -33
- package/dist/lsp/DocumentSymbolProvider.d.ts +0 -1
- package/dist/lsp/DocumentSymbolProvider.js +165 -167
- package/dist/lsp/HoverProvider.d.ts +0 -1
- package/dist/lsp/HoverProvider.js +35 -48
- package/dist/lsp/SemanticTokenProvider.d.ts +0 -1
- package/dist/lsp/SemanticTokenProvider.js +153 -201
- package/dist/lsp/index.d.ts +0 -1
- package/dist/lsp/index.js +5 -6
- package/dist/model/fqn-computation.d.ts +0 -1
- package/dist/model/fqn-computation.js +39 -40
- package/dist/model/fqn-index.d.ts +0 -1
- package/dist/model/fqn-index.js +112 -142
- package/dist/model/index.d.ts +0 -1
- package/dist/model/index.js +5 -6
- package/dist/model/model-builder.d.ts +10 -6
- package/dist/model/model-builder.js +242 -157
- package/dist/model/model-locator.d.ts +1 -2
- package/dist/model/model-locator.js +102 -100
- package/dist/model/model-parser.d.ts +2 -7
- package/dist/model/model-parser.js +296 -287
- package/dist/module.d.ts +4 -2
- package/dist/module.js +69 -60
- package/dist/protocol.d.ts +16 -20
- package/dist/protocol.js +14 -22
- package/dist/references/index.d.ts +0 -1
- package/dist/references/index.js +2 -3
- package/dist/references/scope-computation.d.ts +2 -3
- package/dist/references/scope-computation.js +68 -70
- package/dist/references/scope-provider.d.ts +1 -2
- package/dist/references/scope-provider.js +126 -116
- package/dist/shared/WorkspaceManager.d.ts +2 -4
- package/dist/shared/WorkspaceManager.js +13 -16
- package/dist/shared/index.d.ts +0 -1
- package/dist/shared/index.js +1 -2
- package/dist/test/index.d.ts +0 -1
- package/dist/test/index.js +1 -2
- package/dist/test/testServices.d.ts +6 -7
- package/dist/test/testServices.js +64 -61
- package/dist/utils.d.ts +1 -1
- package/dist/utils.js +4 -3
- package/dist/validation/element.d.ts +0 -2
- package/dist/validation/element.js +28 -39
- package/dist/validation/index.d.ts +0 -1
- package/dist/validation/index.js +36 -46
- package/dist/validation/relation.d.ts +0 -2
- package/dist/validation/relation.js +43 -47
- package/dist/validation/specification.d.ts +0 -2
- package/dist/validation/specification.js +21 -30
- package/dist/validation/view.d.ts +0 -2
- package/dist/validation/view.js +16 -22
- package/package.json +20 -13
- package/contrib/likec4.monarch.ts +0 -48
- package/contrib/likec4.tmLanguage.json +0 -73
- package/dist/registerProtocolHandlers.d.ts +0 -3
- package/dist/registerProtocolHandlers.js +0 -112
|
@@ -1,176 +1,261 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
1
|
+
import {
|
|
2
|
+
ModelIndex,
|
|
3
|
+
assignNavigateTo,
|
|
4
|
+
compareByFqnHierarchically,
|
|
5
|
+
computeView,
|
|
6
|
+
invariant,
|
|
7
|
+
isStrictElementView,
|
|
8
|
+
parentFqn,
|
|
9
|
+
resolveRulesExtendedViews,
|
|
10
|
+
resolveRelativePaths
|
|
11
|
+
} from "@likec4/core";
|
|
12
|
+
import {
|
|
13
|
+
DocumentState,
|
|
14
|
+
interruptAndCheck
|
|
15
|
+
} from "langium";
|
|
16
|
+
import * as R from "remeda";
|
|
17
|
+
import { Disposable } from "vscode-languageserver";
|
|
18
|
+
import { isValidLikeC4LangiumDocument } from "../ast.js";
|
|
19
|
+
import { logError, logWarnError, logger } from "../logger.js";
|
|
20
|
+
import { LikeC4WorkspaceManager } from "../shared/index.js";
|
|
21
|
+
import { printDocs, queueMicrotask } from "../utils.js";
|
|
22
|
+
function isRelativeLink(link) {
|
|
23
|
+
return link.startsWith(".") || link.startsWith("/");
|
|
24
|
+
}
|
|
7
25
|
function buildModel(docs) {
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
26
|
+
const c4Specification = {
|
|
27
|
+
kinds: {}
|
|
28
|
+
};
|
|
29
|
+
R.forEach(
|
|
30
|
+
R.map(docs, R.prop("c4Specification")),
|
|
31
|
+
(spec) => Object.assign(c4Specification.kinds, spec.kinds)
|
|
32
|
+
);
|
|
33
|
+
const resolveLinks = (doc, links) => {
|
|
34
|
+
const base = new URL(doc.uri.toString());
|
|
35
|
+
return links.map(
|
|
36
|
+
(l) => isRelativeLink(l) ? new URL(l, base).toString() : l
|
|
37
|
+
);
|
|
38
|
+
};
|
|
39
|
+
const toModelElement = (doc) => {
|
|
40
|
+
return ({ astPath, tags, links, ...parsed }) => {
|
|
41
|
+
try {
|
|
42
|
+
const kind = c4Specification.kinds[parsed.kind];
|
|
43
|
+
if (kind) {
|
|
44
|
+
return {
|
|
45
|
+
...kind,
|
|
46
|
+
description: null,
|
|
47
|
+
technology: null,
|
|
48
|
+
tags: tags ?? null,
|
|
49
|
+
links: links ? resolveLinks(doc, links) : null,
|
|
50
|
+
...parsed
|
|
51
|
+
};
|
|
52
|
+
}
|
|
53
|
+
} catch (e) {
|
|
54
|
+
logWarnError(e);
|
|
55
|
+
}
|
|
56
|
+
return null;
|
|
34
57
|
};
|
|
35
|
-
|
|
58
|
+
};
|
|
59
|
+
const elements = R.pipe(
|
|
60
|
+
R.flatMap(docs, (d) => d.c4Elements.map(toModelElement(d))),
|
|
61
|
+
R.compact,
|
|
62
|
+
R.sort(compareByFqnHierarchically),
|
|
63
|
+
R.reduce(
|
|
64
|
+
(acc, el) => {
|
|
36
65
|
const parent = parentFqn(el.id);
|
|
37
66
|
if (parent && R.isNil(acc[parent])) {
|
|
38
|
-
|
|
39
|
-
|
|
67
|
+
logWarnError(`No parent found for ${el.id}`);
|
|
68
|
+
return acc;
|
|
40
69
|
}
|
|
41
70
|
if (el.id in acc) {
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
return acc;
|
|
71
|
+
logWarnError(`Duplicate element id: ${el.id}`);
|
|
72
|
+
return acc;
|
|
45
73
|
}
|
|
46
74
|
acc[el.id] = el;
|
|
47
75
|
return acc;
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
76
|
+
},
|
|
77
|
+
{}
|
|
78
|
+
)
|
|
79
|
+
);
|
|
80
|
+
const toModelRelation = ({
|
|
81
|
+
astPath,
|
|
82
|
+
source,
|
|
83
|
+
target,
|
|
84
|
+
...model
|
|
85
|
+
}) => {
|
|
86
|
+
if (source in elements && target in elements) {
|
|
87
|
+
return {
|
|
88
|
+
source,
|
|
89
|
+
target,
|
|
90
|
+
...model
|
|
91
|
+
};
|
|
92
|
+
}
|
|
93
|
+
return null;
|
|
94
|
+
};
|
|
95
|
+
const relations = R.pipe(
|
|
96
|
+
R.flatMap(docs, (d) => d.c4Relations),
|
|
97
|
+
R.map(toModelRelation),
|
|
98
|
+
R.compact,
|
|
99
|
+
R.mapToObj((r) => [r.id, r])
|
|
100
|
+
);
|
|
101
|
+
const toElementView = (doc) => {
|
|
102
|
+
const docUri = doc.uri.toString();
|
|
103
|
+
return (view) => {
|
|
104
|
+
let { astPath, rules, title, description, tags, links, ...model } = view;
|
|
105
|
+
if (!title && "viewOf" in view) {
|
|
106
|
+
title = elements[view.viewOf]?.title;
|
|
107
|
+
}
|
|
108
|
+
if (!title && view.id === "index") {
|
|
109
|
+
title = "Landscape view";
|
|
110
|
+
}
|
|
111
|
+
return {
|
|
112
|
+
...model,
|
|
113
|
+
title: title ?? null,
|
|
114
|
+
description: description ?? null,
|
|
115
|
+
tags: tags ?? null,
|
|
116
|
+
links: links ? resolveLinks(doc, links) : null,
|
|
117
|
+
docUri,
|
|
118
|
+
rules
|
|
119
|
+
};
|
|
58
120
|
};
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
121
|
+
};
|
|
122
|
+
const views = R.pipe(
|
|
123
|
+
R.flatMap(docs, (d) => R.map(d.c4Views, toElementView(d))),
|
|
124
|
+
resolveRelativePaths,
|
|
125
|
+
R.mapToObj((v) => [v.id, v]),
|
|
126
|
+
resolveRulesExtendedViews
|
|
127
|
+
);
|
|
128
|
+
if (!("index" in views)) {
|
|
129
|
+
views["index"] = {
|
|
130
|
+
id: "index",
|
|
131
|
+
title: "Landscape",
|
|
132
|
+
description: null,
|
|
133
|
+
tags: null,
|
|
134
|
+
links: null,
|
|
135
|
+
rules: [
|
|
136
|
+
{
|
|
137
|
+
isInclude: true,
|
|
138
|
+
exprs: [
|
|
139
|
+
{
|
|
140
|
+
wildcard: true
|
|
141
|
+
}
|
|
142
|
+
]
|
|
68
143
|
}
|
|
69
|
-
|
|
70
|
-
...model,
|
|
71
|
-
title: title ?? null,
|
|
72
|
-
description: description ?? null,
|
|
73
|
-
tags: tags ?? null,
|
|
74
|
-
links: links ?? null,
|
|
75
|
-
rules
|
|
76
|
-
};
|
|
77
|
-
};
|
|
78
|
-
const views = R.pipe(R.flatMap(docs, d => d.c4Views), R.map(toElementView), R.compact, R.mapToObj(v => [v.id, v]));
|
|
79
|
-
return {
|
|
80
|
-
elements,
|
|
81
|
-
relations,
|
|
82
|
-
views: resolveRulesExtendedViews(views)
|
|
144
|
+
]
|
|
83
145
|
};
|
|
146
|
+
}
|
|
147
|
+
return {
|
|
148
|
+
elements,
|
|
149
|
+
relations,
|
|
150
|
+
views
|
|
151
|
+
};
|
|
84
152
|
}
|
|
153
|
+
const RAW_MODEL_CACHE = "LikeC4RawModel";
|
|
154
|
+
const MODEL_CACHE = "LikeC4Model";
|
|
85
155
|
export class LikeC4ModelBuilder {
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
return (this.cachedModel.last = buildModel(docs));
|
|
116
|
-
}
|
|
117
|
-
catch (e) {
|
|
118
|
-
logError(e);
|
|
119
|
-
return null;
|
|
120
|
-
}
|
|
121
|
-
}
|
|
122
|
-
buildModel() {
|
|
123
|
-
const model = this.buildRawModel();
|
|
124
|
-
if (!model) {
|
|
125
|
-
return null;
|
|
156
|
+
constructor(services) {
|
|
157
|
+
this.services = services;
|
|
158
|
+
this.langiumDocuments = services.shared.workspace.LangiumDocuments;
|
|
159
|
+
invariant(services.shared.workspace.WorkspaceManager instanceof LikeC4WorkspaceManager);
|
|
160
|
+
this.workspaceManager = services.shared.workspace.WorkspaceManager;
|
|
161
|
+
const parser = services.likec4.ModelParser;
|
|
162
|
+
services.shared.workspace.DocumentBuilder.onBuildPhase(
|
|
163
|
+
DocumentState.Validated,
|
|
164
|
+
async (docs, cancelToken) => {
|
|
165
|
+
await queueMicrotask(() => parser.parse(docs));
|
|
166
|
+
await interruptAndCheck(cancelToken);
|
|
167
|
+
this.notifyListeners(docs.map((d) => d.uri));
|
|
168
|
+
}
|
|
169
|
+
);
|
|
170
|
+
}
|
|
171
|
+
langiumDocuments;
|
|
172
|
+
workspaceManager;
|
|
173
|
+
listeners = [];
|
|
174
|
+
get workspaceUri() {
|
|
175
|
+
return this.workspaceManager.workspace()?.uri ?? null;
|
|
176
|
+
}
|
|
177
|
+
buildRawModel() {
|
|
178
|
+
const cache = this.services.WorkspaceCache;
|
|
179
|
+
return cache.get(RAW_MODEL_CACHE, () => {
|
|
180
|
+
try {
|
|
181
|
+
const docs = this.documents();
|
|
182
|
+
if (docs.length === 0) {
|
|
183
|
+
logger.debug("[ModelBuilder] No documents to build model from");
|
|
184
|
+
return null;
|
|
126
185
|
}
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
186
|
+
logger.debug(`[ModelBuilder] buildModel from ${docs.length} docs:
|
|
187
|
+
${printDocs(docs)}`);
|
|
188
|
+
return buildModel(docs);
|
|
189
|
+
} catch (e) {
|
|
190
|
+
logError(e);
|
|
191
|
+
return null;
|
|
192
|
+
}
|
|
193
|
+
});
|
|
194
|
+
}
|
|
195
|
+
buildModel() {
|
|
196
|
+
const cache = this.services.WorkspaceCache;
|
|
197
|
+
return cache.get(MODEL_CACHE, () => {
|
|
198
|
+
const model = this.buildRawModel();
|
|
199
|
+
if (!model) {
|
|
200
|
+
return null;
|
|
201
|
+
}
|
|
202
|
+
const index = ModelIndex.from(model);
|
|
203
|
+
const views = R.pipe(
|
|
204
|
+
R.values(model.views),
|
|
205
|
+
R.map((view) => computeView(view, index).view),
|
|
206
|
+
R.compact
|
|
207
|
+
);
|
|
208
|
+
assignNavigateTo(views);
|
|
209
|
+
return {
|
|
210
|
+
elements: model.elements,
|
|
211
|
+
relations: model.relations,
|
|
212
|
+
views: R.mapToObj(views, (v) => [v.id, v])
|
|
213
|
+
};
|
|
214
|
+
});
|
|
215
|
+
}
|
|
216
|
+
computeView(viewId) {
|
|
217
|
+
const model = this.buildRawModel();
|
|
218
|
+
const view = model?.views[viewId];
|
|
219
|
+
if (!view) {
|
|
220
|
+
logger.warn(`[ModelBuilder] Cannot find view ${viewId}`);
|
|
221
|
+
return null;
|
|
135
222
|
}
|
|
136
|
-
computeView(
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
logger.warn(`[ModelBuilder] Cannot find view ${viewId}`);
|
|
141
|
-
return null;
|
|
142
|
-
}
|
|
143
|
-
const result = computeView(view, ModelIndex.from(model));
|
|
144
|
-
if (!result.isSuccess) {
|
|
145
|
-
logError(result.error);
|
|
146
|
-
return null;
|
|
147
|
-
}
|
|
148
|
-
const allElementViews = R.values(model.views).filter((v) => isStrictElementView(v) && v.id !== viewId);
|
|
149
|
-
const computedView = result.view;
|
|
150
|
-
computedView.nodes.forEach(node => {
|
|
151
|
-
// find first element view that is not the current one
|
|
152
|
-
const navigateTo = R.find(allElementViews, v => v.viewOf === node.id);
|
|
153
|
-
if (navigateTo) {
|
|
154
|
-
node.navigateTo = navigateTo.id;
|
|
155
|
-
}
|
|
156
|
-
});
|
|
157
|
-
return computedView;
|
|
223
|
+
const result = computeView(view, ModelIndex.from(model));
|
|
224
|
+
if (!result.isSuccess) {
|
|
225
|
+
logError(result.error);
|
|
226
|
+
return null;
|
|
158
227
|
}
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
228
|
+
const allElementViews = R.values(model.views).filter(
|
|
229
|
+
(v) => isStrictElementView(v) && v.id !== viewId
|
|
230
|
+
);
|
|
231
|
+
const computedView = result.view;
|
|
232
|
+
computedView.nodes.forEach((node) => {
|
|
233
|
+
const navigateTo = R.find(allElementViews, (v) => v.viewOf === node.id);
|
|
234
|
+
if (navigateTo) {
|
|
235
|
+
node.navigateTo = navigateTo.id;
|
|
236
|
+
}
|
|
237
|
+
});
|
|
238
|
+
return computedView;
|
|
239
|
+
}
|
|
240
|
+
onModelParsed(callback) {
|
|
241
|
+
this.listeners.push(callback);
|
|
242
|
+
return Disposable.create(() => {
|
|
243
|
+
const index = this.listeners.indexOf(callback);
|
|
244
|
+
if (index >= 0) {
|
|
245
|
+
this.listeners.splice(index, 1);
|
|
246
|
+
}
|
|
247
|
+
});
|
|
248
|
+
}
|
|
249
|
+
documents() {
|
|
250
|
+
return this.langiumDocuments.all.filter(isValidLikeC4LangiumDocument).toArray();
|
|
251
|
+
}
|
|
252
|
+
notifyListeners(docs) {
|
|
253
|
+
for (const listener of this.listeners) {
|
|
254
|
+
try {
|
|
255
|
+
listener(docs);
|
|
256
|
+
} catch (e) {
|
|
257
|
+
logError(e);
|
|
258
|
+
}
|
|
174
259
|
}
|
|
260
|
+
}
|
|
175
261
|
}
|
|
176
|
-
//# sourceMappingURL=model-builder.js.map
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type
|
|
1
|
+
import type { likec4 as c4 } from '@likec4/core';
|
|
2
2
|
import type { Location } from 'vscode-languageserver-protocol';
|
|
3
3
|
import type { ParsedAstElement } from '../ast';
|
|
4
4
|
import { ast } from '../ast';
|
|
@@ -14,4 +14,3 @@ export declare class LikeC4ModelLocator {
|
|
|
14
14
|
locateRelation(relationId: c4.RelationID): Location | null;
|
|
15
15
|
locateView(viewId: c4.ViewID): Location | null;
|
|
16
16
|
}
|
|
17
|
-
//# sourceMappingURL=model-locator.d.ts.map
|
|
@@ -1,111 +1,113 @@
|
|
|
1
|
-
import { InvalidModelError } from
|
|
2
|
-
import { findNodeForProperty, getDocument } from
|
|
3
|
-
import { ast, isParsedLikeC4LangiumDocument } from
|
|
4
|
-
import {} from './fqn-index';
|
|
1
|
+
import { InvalidModelError } from "@likec4/core";
|
|
2
|
+
import { findNodeForProperty, getDocument } from "langium";
|
|
3
|
+
import { ast, isParsedLikeC4LangiumDocument } from "../ast.js";
|
|
5
4
|
export class LikeC4ModelLocator {
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
5
|
+
constructor(services) {
|
|
6
|
+
this.services = services;
|
|
7
|
+
this.fqnIndex = services.likec4.FqnIndex;
|
|
8
|
+
this.langiumDocuments = services.shared.workspace.LangiumDocuments;
|
|
9
|
+
}
|
|
10
|
+
fqnIndex;
|
|
11
|
+
langiumDocuments;
|
|
12
|
+
documents() {
|
|
13
|
+
return this.langiumDocuments.all.filter(isParsedLikeC4LangiumDocument);
|
|
14
|
+
}
|
|
15
|
+
getParsedElement(astNode) {
|
|
16
|
+
const fqn = this.fqnIndex.getFqn(astNode);
|
|
17
|
+
if (!fqn)
|
|
18
|
+
return null;
|
|
19
|
+
const doc = getDocument(astNode);
|
|
20
|
+
if (!isParsedLikeC4LangiumDocument(doc)) {
|
|
21
|
+
return null;
|
|
13
22
|
}
|
|
14
|
-
|
|
15
|
-
|
|
23
|
+
return doc.c4Elements.find((e) => e.id === fqn) ?? null;
|
|
24
|
+
}
|
|
25
|
+
locateElement(fqn, property = "name") {
|
|
26
|
+
const entry = this.fqnIndex.byFqn(fqn).head();
|
|
27
|
+
if (!entry) {
|
|
28
|
+
return null;
|
|
16
29
|
}
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
return null;
|
|
21
|
-
const doc = getDocument(astNode);
|
|
22
|
-
if (!isParsedLikeC4LangiumDocument(doc)) {
|
|
23
|
-
return null;
|
|
24
|
-
}
|
|
25
|
-
return doc.c4Elements.find(e => e.id === fqn) ?? null;
|
|
26
|
-
}
|
|
27
|
-
locateElement(fqn, property = 'name') {
|
|
28
|
-
const entry = this.fqnIndex.byFqn(fqn).head();
|
|
29
|
-
if (!entry) {
|
|
30
|
-
return null;
|
|
31
|
-
}
|
|
32
|
-
const propertyNode = findNodeForProperty(entry.el.$cstNode, property) ?? entry.el.$cstNode;
|
|
33
|
-
if (!propertyNode) {
|
|
34
|
-
return null;
|
|
35
|
-
}
|
|
36
|
-
return {
|
|
37
|
-
uri: entry.doc.uri.toString(),
|
|
38
|
-
range: propertyNode.range
|
|
39
|
-
};
|
|
30
|
+
const propertyNode = findNodeForProperty(entry.el.$cstNode, property) ?? entry.el.$cstNode;
|
|
31
|
+
if (!propertyNode) {
|
|
32
|
+
return null;
|
|
40
33
|
}
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
if (!targetNode) {
|
|
68
|
-
return null;
|
|
34
|
+
return {
|
|
35
|
+
uri: entry.doc.uri.toString(),
|
|
36
|
+
range: propertyNode.range
|
|
37
|
+
};
|
|
38
|
+
}
|
|
39
|
+
locateRelation(relationId) {
|
|
40
|
+
for (const doc of this.documents()) {
|
|
41
|
+
const relation = doc.c4Relations.find((r) => r.id === relationId);
|
|
42
|
+
if (!relation) {
|
|
43
|
+
continue;
|
|
44
|
+
}
|
|
45
|
+
const node = this.services.workspace.AstNodeLocator.getAstNode(
|
|
46
|
+
doc.parseResult.value,
|
|
47
|
+
relation.astPath
|
|
48
|
+
);
|
|
49
|
+
if (!ast.isRelation(node)) {
|
|
50
|
+
continue;
|
|
51
|
+
}
|
|
52
|
+
if (node.title) {
|
|
53
|
+
const targetNode2 = findNodeForProperty(node.$cstNode, "title");
|
|
54
|
+
if (targetNode2) {
|
|
55
|
+
return {
|
|
56
|
+
uri: doc.uri.toString(),
|
|
57
|
+
range: {
|
|
58
|
+
start: targetNode2.range.start,
|
|
59
|
+
end: targetNode2.range.start
|
|
69
60
|
}
|
|
70
|
-
|
|
71
|
-
uri: doc.uri.toString(),
|
|
72
|
-
range: {
|
|
73
|
-
start: targetNode.range.start,
|
|
74
|
-
end: targetNode.range.end
|
|
75
|
-
}
|
|
76
|
-
};
|
|
61
|
+
};
|
|
77
62
|
}
|
|
63
|
+
}
|
|
64
|
+
if (node.arr == null) {
|
|
65
|
+
throw new InvalidModelError("Relation.arr is not defined, but should be");
|
|
66
|
+
}
|
|
67
|
+
const targetNode = findNodeForProperty(node.$cstNode, "arr");
|
|
68
|
+
if (!targetNode) {
|
|
78
69
|
return null;
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
}
|
|
86
|
-
const node = this.services.workspace.AstNodeLocator.getAstNode(doc.parseResult.value, view.astPath);
|
|
87
|
-
if (!ast.isElementView(node)) {
|
|
88
|
-
continue;
|
|
89
|
-
}
|
|
90
|
-
let targetNode = node.$cstNode;
|
|
91
|
-
if (node.name) {
|
|
92
|
-
targetNode = findNodeForProperty(node.$cstNode, 'name') ?? targetNode;
|
|
93
|
-
}
|
|
94
|
-
else if ('viewOf' in node) {
|
|
95
|
-
targetNode = findNodeForProperty(node.$cstNode, 'viewOf') ?? targetNode;
|
|
96
|
-
}
|
|
97
|
-
if (!targetNode) {
|
|
98
|
-
return null;
|
|
99
|
-
}
|
|
100
|
-
return {
|
|
101
|
-
uri: doc.uri.toString(),
|
|
102
|
-
range: {
|
|
103
|
-
start: targetNode.range.start,
|
|
104
|
-
end: targetNode.range.start
|
|
105
|
-
}
|
|
106
|
-
};
|
|
70
|
+
}
|
|
71
|
+
return {
|
|
72
|
+
uri: doc.uri.toString(),
|
|
73
|
+
range: {
|
|
74
|
+
start: targetNode.range.start,
|
|
75
|
+
end: targetNode.range.end
|
|
107
76
|
}
|
|
77
|
+
};
|
|
78
|
+
}
|
|
79
|
+
return null;
|
|
80
|
+
}
|
|
81
|
+
locateView(viewId) {
|
|
82
|
+
for (const doc of this.documents()) {
|
|
83
|
+
const view = doc.c4Views.find((r) => r.id === viewId);
|
|
84
|
+
if (!view) {
|
|
85
|
+
continue;
|
|
86
|
+
}
|
|
87
|
+
const node = this.services.workspace.AstNodeLocator.getAstNode(
|
|
88
|
+
doc.parseResult.value,
|
|
89
|
+
view.astPath
|
|
90
|
+
);
|
|
91
|
+
if (!ast.isElementView(node)) {
|
|
92
|
+
continue;
|
|
93
|
+
}
|
|
94
|
+
let targetNode = node.$cstNode;
|
|
95
|
+
if (node.name) {
|
|
96
|
+
targetNode = findNodeForProperty(node.$cstNode, "name") ?? targetNode;
|
|
97
|
+
} else if ("viewOf" in node) {
|
|
98
|
+
targetNode = findNodeForProperty(node.$cstNode, "viewOf") ?? targetNode;
|
|
99
|
+
}
|
|
100
|
+
if (!targetNode) {
|
|
108
101
|
return null;
|
|
102
|
+
}
|
|
103
|
+
return {
|
|
104
|
+
uri: doc.uri.toString(),
|
|
105
|
+
range: {
|
|
106
|
+
start: targetNode.range.start,
|
|
107
|
+
end: targetNode.range.start
|
|
108
|
+
}
|
|
109
|
+
};
|
|
109
110
|
}
|
|
111
|
+
return null;
|
|
112
|
+
}
|
|
110
113
|
}
|
|
111
|
-
//# sourceMappingURL=model-locator.js.map
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import { type c4 } from '@likec4/core';
|
|
2
2
|
import type { LangiumDocument } from 'langium';
|
|
3
|
-
import { Disposable, type CancellationToken } from 'vscode-languageserver-protocol';
|
|
4
3
|
import type { LikeC4LangiumDocument } from '../ast';
|
|
5
4
|
import { ast } from '../ast';
|
|
6
5
|
import type { LikeC4Services } from '../module';
|
|
@@ -8,11 +7,9 @@ export type ModelParsedListener = () => void;
|
|
|
8
7
|
export declare class LikeC4ModelParser {
|
|
9
8
|
private services;
|
|
10
9
|
private fqnIndex;
|
|
11
|
-
protected readonly listeners: ModelParsedListener[];
|
|
12
10
|
constructor(services: LikeC4Services);
|
|
13
|
-
|
|
14
|
-
protected
|
|
15
|
-
protected parseDocument(doc: LikeC4LangiumDocument, cancelToken: CancellationToken): Promise<void>;
|
|
11
|
+
parse(doc: LangiumDocument | LangiumDocument[]): void;
|
|
12
|
+
protected parseLikeC4Document(doc: LikeC4LangiumDocument): void;
|
|
16
13
|
private parseElement;
|
|
17
14
|
private parseRelation;
|
|
18
15
|
private parseElementExpression;
|
|
@@ -22,6 +19,4 @@ export declare class LikeC4ModelParser {
|
|
|
22
19
|
protected resolveFqn(node: ast.Element | ast.ExtendElement): c4.Fqn;
|
|
23
20
|
private getAstNodePath;
|
|
24
21
|
private convertTags;
|
|
25
|
-
private notifyListeners;
|
|
26
22
|
}
|
|
27
|
-
//# sourceMappingURL=model-parser.d.ts.map
|