@likec4/language-server 1.9.0 → 1.10.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/contrib/likec4.tmLanguage.json +1 -1
- package/dist/browser.cjs +1 -1
- package/dist/browser.d.cts +1 -1
- package/dist/browser.d.mts +1 -1
- package/dist/browser.d.ts +1 -1
- package/dist/browser.mjs +1 -1
- package/dist/index.cjs +1 -1
- package/dist/index.d.cts +2 -2
- package/dist/index.d.mts +2 -2
- package/dist/index.d.ts +2 -2
- package/dist/index.mjs +1 -1
- package/dist/model-graph/index.cjs +1 -1
- package/dist/model-graph/index.mjs +1 -1
- package/dist/node.cjs +1 -1
- package/dist/node.d.cts +1 -1
- package/dist/node.d.mts +1 -1
- package/dist/node.d.ts +1 -1
- package/dist/node.mjs +1 -1
- package/dist/shared/{language-server.86lmJ8ZN.d.cts → language-server.CjFzaJwI.d.cts} +42 -13
- package/dist/shared/{language-server.RjhrBZS0.d.ts → language-server.CtKHXJDD.d.ts} +42 -13
- package/dist/shared/{language-server.CFTY6j4e.d.mts → language-server.D-84I33F.d.mts} +42 -13
- package/dist/shared/{language-server.Q-wtPShM.mjs → language-server.DBJJUUgF.mjs} +485 -108
- package/dist/shared/{language-server.CCB4ESN5.mjs → language-server.DtBRb9os.mjs} +166 -116
- package/dist/shared/{language-server.D0bOlrCi.cjs → language-server.DwyCJvXm.cjs} +164 -114
- package/dist/shared/{language-server.B1TZgyoH.cjs → language-server.JWkqVjGv.cjs} +481 -104
- package/package.json +6 -5
- package/src/ast.ts +8 -6
- package/src/formatting/LikeC4Formatter.ts +388 -0
- package/src/formatting/utils.ts +26 -0
- package/src/generated/ast.ts +104 -10
- package/src/generated/grammar.ts +1 -1
- package/src/like-c4.langium +34 -7
- package/src/lsp/DocumentLinkProvider.ts +27 -15
- package/src/lsp/SemanticTokenProvider.ts +1 -1
- package/src/lsp/index.ts +1 -1
- package/src/model/fqn-index.ts +0 -1
- package/src/model/model-builder.ts +43 -32
- package/src/model/model-parser.ts +43 -21
- package/src/model-graph/compute-view/compute.ts +104 -78
- package/src/model-graph/compute-view/predicates.ts +3 -5
- package/src/model-graph/dynamic-view/compute.ts +96 -60
- package/src/model-graph/utils/buildElementNotations.ts +1 -1
- package/src/module.ts +6 -9
- package/src/test/testServices.ts +27 -7
- package/src/validation/index.ts +2 -1
- package/src/validation/property-checks.ts +13 -1
- package/src/validation/specification.ts +3 -3
- package/src/view-utils/resolve-relative-paths.ts +14 -17
|
@@ -295,8 +295,8 @@ function buildElementNotations(nodes) {
|
|
|
295
295
|
}))
|
|
296
296
|
),
|
|
297
297
|
remeda.sortBy(
|
|
298
|
-
remeda.prop("title"),
|
|
299
298
|
remeda.prop("shape"),
|
|
299
|
+
remeda.prop("title"),
|
|
300
300
|
[
|
|
301
301
|
(n) => n.kinds.length,
|
|
302
302
|
"desc"
|
|
@@ -621,13 +621,11 @@ const filterEdges = (edges, where) => {
|
|
|
621
621
|
);
|
|
622
622
|
};
|
|
623
623
|
const filterRelations = (edges, where) => {
|
|
624
|
-
if (!where) {
|
|
625
|
-
return edges.flatMap((e) => e.relations);
|
|
626
|
-
}
|
|
627
624
|
return remeda.pipe(
|
|
628
625
|
edges,
|
|
629
626
|
remeda.flatMap((e) => e.relations),
|
|
630
|
-
remeda.filter(where)
|
|
627
|
+
where ? remeda.filter(where) : Identity,
|
|
628
|
+
remeda.unique()
|
|
631
629
|
);
|
|
632
630
|
};
|
|
633
631
|
function includeIncomingExpr(expr, where) {
|
|
@@ -875,7 +873,7 @@ class ComputeCtx {
|
|
|
875
873
|
computeEdges() {
|
|
876
874
|
return this.ctxEdges.map((e) => {
|
|
877
875
|
core.invariant(remeda.hasAtLeast(e.relations, 1), "Edge must have at least one relation");
|
|
878
|
-
const relations = e.relations
|
|
876
|
+
const relations = remeda.sort(e.relations, core.compareRelations);
|
|
879
877
|
const source = e.source.id;
|
|
880
878
|
const target = e.target.id;
|
|
881
879
|
const edge = {
|
|
@@ -887,48 +885,62 @@ class ComputeCtx {
|
|
|
887
885
|
relations: relations.map((r) => r.id)
|
|
888
886
|
};
|
|
889
887
|
let relation;
|
|
890
|
-
|
|
891
|
-
relation = relations[0];
|
|
892
|
-
} else {
|
|
893
|
-
relation = relations.find((r) => r.source === source && r.target === target);
|
|
894
|
-
}
|
|
888
|
+
relation = relations.length === 1 ? relations[0] : relations.find((r) => r.source === source && r.target === target);
|
|
895
889
|
if (!relation) {
|
|
896
|
-
|
|
897
|
-
|
|
898
|
-
|
|
899
|
-
|
|
900
|
-
|
|
901
|
-
|
|
902
|
-
|
|
903
|
-
|
|
904
|
-
|
|
905
|
-
|
|
906
|
-
|
|
907
|
-
|
|
908
|
-
|
|
909
|
-
|
|
910
|
-
|
|
911
|
-
|
|
912
|
-
|
|
913
|
-
|
|
914
|
-
|
|
915
|
-
|
|
916
|
-
|
|
917
|
-
|
|
918
|
-
|
|
919
|
-
|
|
920
|
-
|
|
921
|
-
|
|
922
|
-
|
|
923
|
-
|
|
924
|
-
|
|
925
|
-
|
|
926
|
-
|
|
927
|
-
|
|
928
|
-
|
|
929
|
-
|
|
930
|
-
|
|
931
|
-
|
|
890
|
+
const allprops = remeda.pipe(
|
|
891
|
+
relations,
|
|
892
|
+
remeda.reduce((acc, r) => {
|
|
893
|
+
if (remeda.isTruthy(r.title) && !acc.title.includes(r.title)) {
|
|
894
|
+
acc.title.push(r.title);
|
|
895
|
+
}
|
|
896
|
+
if (remeda.isTruthy(r.description) && !acc.description.includes(r.description)) {
|
|
897
|
+
acc.description.push(r.description);
|
|
898
|
+
}
|
|
899
|
+
if (remeda.isTruthy(r.technology) && !acc.technology.includes(r.technology)) {
|
|
900
|
+
acc.technology.push(r.technology);
|
|
901
|
+
}
|
|
902
|
+
if (remeda.isTruthy(r.kind) && !acc.kind.includes(r.kind)) {
|
|
903
|
+
acc.kind.push(r.kind);
|
|
904
|
+
}
|
|
905
|
+
if (remeda.isTruthy(r.color) && !acc.color.includes(r.color)) {
|
|
906
|
+
acc.color.push(r.color);
|
|
907
|
+
}
|
|
908
|
+
if (remeda.isTruthy(r.line) && !acc.line.includes(r.line)) {
|
|
909
|
+
acc.line.push(r.line);
|
|
910
|
+
}
|
|
911
|
+
if (remeda.isTruthy(r.head) && !acc.head.includes(r.head)) {
|
|
912
|
+
acc.head.push(r.head);
|
|
913
|
+
}
|
|
914
|
+
if (remeda.isTruthy(r.tail) && !acc.tail.includes(r.tail)) {
|
|
915
|
+
acc.tail.push(r.tail);
|
|
916
|
+
}
|
|
917
|
+
if (remeda.isTruthy(r.navigateTo) && !acc.navigateTo.includes(r.navigateTo)) {
|
|
918
|
+
acc.navigateTo.push(r.navigateTo);
|
|
919
|
+
}
|
|
920
|
+
return acc;
|
|
921
|
+
}, {
|
|
922
|
+
title: [],
|
|
923
|
+
description: [],
|
|
924
|
+
technology: [],
|
|
925
|
+
kind: [],
|
|
926
|
+
head: [],
|
|
927
|
+
tail: [],
|
|
928
|
+
color: [],
|
|
929
|
+
line: [],
|
|
930
|
+
navigateTo: []
|
|
931
|
+
})
|
|
932
|
+
);
|
|
933
|
+
relation = {
|
|
934
|
+
title: remeda.only(allprops.title) ?? "[...]",
|
|
935
|
+
description: remeda.only(allprops.description),
|
|
936
|
+
technology: remeda.only(allprops.technology),
|
|
937
|
+
kind: remeda.only(allprops.kind),
|
|
938
|
+
head: remeda.only(allprops.head),
|
|
939
|
+
tail: remeda.only(allprops.tail),
|
|
940
|
+
color: remeda.only(allprops.color),
|
|
941
|
+
line: remeda.only(allprops.line),
|
|
942
|
+
navigateTo: remeda.only(allprops.navigateTo)
|
|
943
|
+
};
|
|
932
944
|
}
|
|
933
945
|
const tags = remeda.unique(remeda.flatMap(relations, (r) => r.tags ?? []));
|
|
934
946
|
return Object.assign(
|
|
@@ -941,6 +953,7 @@ class ComputeCtx {
|
|
|
941
953
|
relation.line && { line: relation.line },
|
|
942
954
|
relation.head && { head: relation.head },
|
|
943
955
|
relation.tail && { tail: relation.tail },
|
|
956
|
+
relation.navigateTo && { navigateTo: relation.navigateTo },
|
|
944
957
|
remeda.hasAtLeast(tags, 1) && { tags }
|
|
945
958
|
);
|
|
946
959
|
});
|
|
@@ -1002,28 +1015,39 @@ class ComputeCtx {
|
|
|
1002
1015
|
this.implicits.delete(el);
|
|
1003
1016
|
}
|
|
1004
1017
|
}
|
|
1005
|
-
excludeImplicit(...excludes) {
|
|
1006
|
-
|
|
1007
|
-
|
|
1008
|
-
|
|
1009
|
-
}
|
|
1018
|
+
// protected excludeImplicit(...excludes: Element[]) {
|
|
1019
|
+
// for (const el of excludes) {
|
|
1020
|
+
// this.implicits.delete(el)
|
|
1021
|
+
// }
|
|
1022
|
+
// }
|
|
1010
1023
|
excludeRelation(...relations) {
|
|
1024
|
+
if (relations.length === 0) {
|
|
1025
|
+
return;
|
|
1026
|
+
}
|
|
1011
1027
|
const excludedImplicits = /* @__PURE__ */ new Set();
|
|
1012
|
-
|
|
1013
|
-
|
|
1014
|
-
|
|
1015
|
-
|
|
1028
|
+
const ctxEdges = remeda.pipe(
|
|
1029
|
+
this.ctxEdges,
|
|
1030
|
+
remeda.map((edge) => {
|
|
1031
|
+
const edgerelations = edge.relations.filter((r) => !relations.includes(r));
|
|
1032
|
+
if (edgerelations.length === 0) {
|
|
1016
1033
|
excludedImplicits.add(edge.source);
|
|
1017
1034
|
excludedImplicits.add(edge.target);
|
|
1018
|
-
|
|
1019
|
-
continue;
|
|
1035
|
+
return null;
|
|
1020
1036
|
}
|
|
1021
|
-
|
|
1022
|
-
|
|
1023
|
-
|
|
1037
|
+
if (edgerelations.length !== edge.relations.length) {
|
|
1038
|
+
return {
|
|
1039
|
+
...edge,
|
|
1040
|
+
relations: edgerelations
|
|
1041
|
+
};
|
|
1042
|
+
}
|
|
1043
|
+
return edge;
|
|
1044
|
+
}),
|
|
1045
|
+
remeda.filter(remeda.isNonNull)
|
|
1046
|
+
);
|
|
1024
1047
|
if (excludedImplicits.size === 0) {
|
|
1025
1048
|
return;
|
|
1026
1049
|
}
|
|
1050
|
+
this.ctxEdges = ctxEdges;
|
|
1027
1051
|
const remaining = this.includedElements;
|
|
1028
1052
|
if (remaining.size === 0) {
|
|
1029
1053
|
this.implicits.clear();
|
|
@@ -1167,7 +1191,7 @@ class ComputeCtx {
|
|
|
1167
1191
|
if (remeda.isTruthy(relation.technology)) {
|
|
1168
1192
|
labelParts.push(`[${relation.technology}]`);
|
|
1169
1193
|
}
|
|
1170
|
-
return labelParts.length > 0
|
|
1194
|
+
return labelParts.length > 0 ? { label: labelParts.join("\n") } : {};
|
|
1171
1195
|
}
|
|
1172
1196
|
}
|
|
1173
1197
|
|
|
@@ -1200,6 +1224,38 @@ class DynamicViewComputeCtx {
|
|
|
1200
1224
|
static compute(view, graph) {
|
|
1201
1225
|
return new DynamicViewComputeCtx(view, graph).compute();
|
|
1202
1226
|
}
|
|
1227
|
+
addStep({
|
|
1228
|
+
source: stepSource,
|
|
1229
|
+
target: stepTarget,
|
|
1230
|
+
title: stepTitle,
|
|
1231
|
+
isBackward,
|
|
1232
|
+
navigateTo: stepNavigateTo,
|
|
1233
|
+
...step
|
|
1234
|
+
}, index, parent) {
|
|
1235
|
+
const id = parent ? core.StepEdgeId(parent, index) : core.StepEdgeId(index);
|
|
1236
|
+
const source = this.graph.element(stepSource);
|
|
1237
|
+
const target = this.graph.element(stepTarget);
|
|
1238
|
+
this.explicits.add(source);
|
|
1239
|
+
this.explicits.add(target);
|
|
1240
|
+
const {
|
|
1241
|
+
title,
|
|
1242
|
+
relations,
|
|
1243
|
+
tags,
|
|
1244
|
+
navigateTo: derivedNavigateTo
|
|
1245
|
+
} = this.findRelations(source, target);
|
|
1246
|
+
const navigateTo = remeda.isTruthy(stepNavigateTo) && stepNavigateTo !== this.view.id ? stepNavigateTo : derivedNavigateTo;
|
|
1247
|
+
this.steps.push({
|
|
1248
|
+
id,
|
|
1249
|
+
...step,
|
|
1250
|
+
source,
|
|
1251
|
+
target,
|
|
1252
|
+
title: stepTitle ?? title,
|
|
1253
|
+
relations: relations ?? [],
|
|
1254
|
+
isBackward: isBackward ?? false,
|
|
1255
|
+
...navigateTo ? { navigateTo } : {},
|
|
1256
|
+
...tags ? { tags } : {}
|
|
1257
|
+
});
|
|
1258
|
+
}
|
|
1203
1259
|
compute() {
|
|
1204
1260
|
const {
|
|
1205
1261
|
docUri: _docUri,
|
|
@@ -1208,27 +1264,21 @@ class DynamicViewComputeCtx {
|
|
|
1208
1264
|
steps: viewSteps,
|
|
1209
1265
|
...view
|
|
1210
1266
|
} = this.view;
|
|
1211
|
-
|
|
1212
|
-
|
|
1213
|
-
|
|
1214
|
-
|
|
1215
|
-
|
|
1216
|
-
|
|
1217
|
-
|
|
1218
|
-
|
|
1219
|
-
|
|
1220
|
-
|
|
1221
|
-
|
|
1222
|
-
|
|
1223
|
-
|
|
1224
|
-
|
|
1225
|
-
|
|
1226
|
-
target,
|
|
1227
|
-
title: remeda.isTruthy(stepTitle) ? stepTitle : title,
|
|
1228
|
-
relations: relations ?? [],
|
|
1229
|
-
isBackward: isBackward ?? false,
|
|
1230
|
-
...tags ? { tags } : {}
|
|
1231
|
-
});
|
|
1267
|
+
let stepNum = 1;
|
|
1268
|
+
for (const step of viewSteps) {
|
|
1269
|
+
if (core.isDynamicViewParallelSteps(step)) {
|
|
1270
|
+
if (step.__parallel.length === 0) {
|
|
1271
|
+
continue;
|
|
1272
|
+
}
|
|
1273
|
+
if (step.__parallel.length === 1) {
|
|
1274
|
+
this.addStep(step.__parallel[0], stepNum);
|
|
1275
|
+
} else {
|
|
1276
|
+
step.__parallel.forEach((s, i) => this.addStep(s, i + 1, stepNum));
|
|
1277
|
+
}
|
|
1278
|
+
} else {
|
|
1279
|
+
this.addStep(step, stepNum);
|
|
1280
|
+
}
|
|
1281
|
+
stepNum++;
|
|
1232
1282
|
}
|
|
1233
1283
|
for (const rule of rules) {
|
|
1234
1284
|
if (core.isDynamicViewIncludeRule(rule)) {
|
|
@@ -1240,12 +1290,10 @@ class DynamicViewComputeCtx {
|
|
|
1240
1290
|
}
|
|
1241
1291
|
const elements = [...this.explicits];
|
|
1242
1292
|
const nodesMap = buildComputeNodes(elements);
|
|
1243
|
-
const edges = this.steps.map(({ source, target, relations, title, isBackward, ...step }
|
|
1293
|
+
const edges = this.steps.map(({ source, target, relations, title, isBackward, ...step }) => {
|
|
1244
1294
|
const sourceNode = core.nonNullable(nodesMap.get(source.id), `Source node ${source.id} not found`);
|
|
1245
1295
|
const targetNode = core.nonNullable(nodesMap.get(target.id), `Target node ${target.id} not found`);
|
|
1246
|
-
const stepNum = index + 1;
|
|
1247
1296
|
const edge = {
|
|
1248
|
-
id: core.StepEdgeId(stepNum),
|
|
1249
1297
|
parent: core.commonAncestor(source.id, target.id),
|
|
1250
1298
|
source: source.id,
|
|
1251
1299
|
target: target.id,
|
|
@@ -1302,41 +1350,43 @@ class DynamicViewComputeCtx {
|
|
|
1302
1350
|
}
|
|
1303
1351
|
findRelations(source, target) {
|
|
1304
1352
|
const relationships = remeda.unique(this.graph.edgesBetween(source, target).flatMap((e) => e.relations));
|
|
1305
|
-
const alltags = remeda.unique(relationships.flatMap((r) => r.tags ?? []));
|
|
1306
|
-
const tags = remeda.hasAtLeast(alltags, 1) ? alltags : null;
|
|
1307
|
-
const relations = remeda.hasAtLeast(relationships, 1) ? remeda.map(relationships, (r) => r.id) : null;
|
|
1308
1353
|
if (relationships.length === 0) {
|
|
1309
1354
|
return {
|
|
1310
1355
|
title: null,
|
|
1311
|
-
tags,
|
|
1312
|
-
relations
|
|
1313
|
-
|
|
1314
|
-
}
|
|
1315
|
-
let relation;
|
|
1316
|
-
if (relationships.length === 1) {
|
|
1317
|
-
relation = relationships[0];
|
|
1318
|
-
} else {
|
|
1319
|
-
relation = relationships.find((r) => r.source === source.id && r.target === target.id);
|
|
1320
|
-
}
|
|
1321
|
-
if (relation && remeda.isTruthy(relation.title)) {
|
|
1322
|
-
return {
|
|
1323
|
-
title: relation.title,
|
|
1324
|
-
tags,
|
|
1325
|
-
relations
|
|
1326
|
-
};
|
|
1327
|
-
}
|
|
1328
|
-
const labels = remeda.unique(relationships.flatMap((r) => remeda.isTruthy(r.title) ? r.title : []));
|
|
1329
|
-
if (labels.length === 1) {
|
|
1330
|
-
return {
|
|
1331
|
-
title: labels[0],
|
|
1332
|
-
tags,
|
|
1333
|
-
relations
|
|
1356
|
+
tags: null,
|
|
1357
|
+
relations: null,
|
|
1358
|
+
navigateTo: null
|
|
1334
1359
|
};
|
|
1335
1360
|
}
|
|
1361
|
+
const alltags = remeda.pipe(
|
|
1362
|
+
relationships,
|
|
1363
|
+
remeda.flatMap((r) => r.tags),
|
|
1364
|
+
remeda.filter(remeda.isTruthy),
|
|
1365
|
+
remeda.unique()
|
|
1366
|
+
);
|
|
1367
|
+
const tags = remeda.hasAtLeast(alltags, 1) ? alltags : null;
|
|
1368
|
+
const relations = remeda.hasAtLeast(relationships, 1) ? remeda.map(relationships, (r) => r.id) : null;
|
|
1369
|
+
const relation = remeda.only(relationships) || relationships.find((r) => r.source === source.id && r.target === target.id);
|
|
1370
|
+
const title = remeda.isTruthy(relation?.title) ? relation.title : remeda.pipe(
|
|
1371
|
+
relationships,
|
|
1372
|
+
remeda.map((r) => r.title),
|
|
1373
|
+
remeda.filter(remeda.isTruthy),
|
|
1374
|
+
remeda.unique(),
|
|
1375
|
+
remeda.only()
|
|
1376
|
+
);
|
|
1377
|
+
const navigateTo = !!relation?.navigateTo && relation.navigateTo !== this.view.id ? relation.navigateTo : remeda.pipe(
|
|
1378
|
+
relationships,
|
|
1379
|
+
remeda.map((r) => r.navigateTo),
|
|
1380
|
+
remeda.filter(remeda.isTruthy),
|
|
1381
|
+
remeda.filter((v) => v !== this.view.id),
|
|
1382
|
+
remeda.unique(),
|
|
1383
|
+
remeda.only()
|
|
1384
|
+
);
|
|
1336
1385
|
return {
|
|
1337
|
-
title: null,
|
|
1386
|
+
title: title ?? null,
|
|
1338
1387
|
tags,
|
|
1339
|
-
relations
|
|
1388
|
+
relations,
|
|
1389
|
+
navigateTo: navigateTo ?? null
|
|
1340
1390
|
};
|
|
1341
1391
|
}
|
|
1342
1392
|
}
|