@likec4/language-server 0.37.1 → 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 -177
- 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,196 +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
|
-
// add index view if not present
|
|
80
|
-
if (!('index' in views)) {
|
|
81
|
-
views['index'] = {
|
|
82
|
-
id: 'index',
|
|
83
|
-
title: 'Landscape',
|
|
84
|
-
description: null,
|
|
85
|
-
tags: null,
|
|
86
|
-
links: null,
|
|
87
|
-
rules: [
|
|
88
|
-
{
|
|
89
|
-
isInclude: true,
|
|
90
|
-
exprs: [
|
|
91
|
-
{
|
|
92
|
-
wildcard: true
|
|
93
|
-
}
|
|
94
|
-
]
|
|
95
|
-
}
|
|
96
|
-
]
|
|
97
|
-
};
|
|
98
|
-
}
|
|
99
|
-
return {
|
|
100
|
-
elements,
|
|
101
|
-
relations,
|
|
102
|
-
views: resolveRulesExtendedViews(views)
|
|
144
|
+
]
|
|
103
145
|
};
|
|
146
|
+
}
|
|
147
|
+
return {
|
|
148
|
+
elements,
|
|
149
|
+
relations,
|
|
150
|
+
views
|
|
151
|
+
};
|
|
104
152
|
}
|
|
153
|
+
const RAW_MODEL_CACHE = "LikeC4RawModel";
|
|
154
|
+
const MODEL_CACHE = "LikeC4Model";
|
|
105
155
|
export class LikeC4ModelBuilder {
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
return (this.cachedModel.last = buildModel(docs));
|
|
136
|
-
}
|
|
137
|
-
catch (e) {
|
|
138
|
-
logError(e);
|
|
139
|
-
return null;
|
|
140
|
-
}
|
|
141
|
-
}
|
|
142
|
-
buildModel() {
|
|
143
|
-
const model = this.buildRawModel();
|
|
144
|
-
if (!model) {
|
|
145
|
-
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;
|
|
146
185
|
}
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
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;
|
|
155
222
|
}
|
|
156
|
-
computeView(
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
logger.warn(`[ModelBuilder] Cannot find view ${viewId}`);
|
|
161
|
-
return null;
|
|
162
|
-
}
|
|
163
|
-
const result = computeView(view, ModelIndex.from(model));
|
|
164
|
-
if (!result.isSuccess) {
|
|
165
|
-
logError(result.error);
|
|
166
|
-
return null;
|
|
167
|
-
}
|
|
168
|
-
const allElementViews = R.values(model.views).filter((v) => isStrictElementView(v) && v.id !== viewId);
|
|
169
|
-
const computedView = result.view;
|
|
170
|
-
computedView.nodes.forEach(node => {
|
|
171
|
-
// find first element view that is not the current one
|
|
172
|
-
const navigateTo = R.find(allElementViews, v => v.viewOf === node.id);
|
|
173
|
-
if (navigateTo) {
|
|
174
|
-
node.navigateTo = navigateTo.id;
|
|
175
|
-
}
|
|
176
|
-
});
|
|
177
|
-
return computedView;
|
|
223
|
+
const result = computeView(view, ModelIndex.from(model));
|
|
224
|
+
if (!result.isSuccess) {
|
|
225
|
+
logError(result.error);
|
|
226
|
+
return null;
|
|
178
227
|
}
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
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
|
+
}
|
|
194
259
|
}
|
|
260
|
+
}
|
|
195
261
|
}
|
|
196
|
-
//# 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
|