@likec4/language-server 1.15.1 → 1.17.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 +2 -2
- package/dist/browser.d.mts +2 -2
- package/dist/browser.d.ts +2 -2
- package/dist/browser.mjs +2 -2
- package/dist/index.cjs +35 -5
- package/dist/index.d.cts +17 -4
- package/dist/index.d.mts +17 -4
- package/dist/index.d.ts +17 -4
- package/dist/index.mjs +34 -5
- package/dist/model-graph/index.cjs +1 -1
- package/dist/model-graph/index.d.cts +4 -2
- package/dist/model-graph/index.d.mts +4 -2
- package/dist/model-graph/index.d.ts +4 -2
- package/dist/model-graph/index.mjs +1 -1
- package/dist/shared/{language-server.BuChFlda.mjs → language-server.B8qSDsWW.mjs} +211 -96
- package/dist/shared/language-server.BGGRJRnr.d.mts +1338 -0
- package/dist/shared/{language-server.BT4WTbFI.mjs → language-server.BXFhlTPo.mjs} +139 -76
- package/dist/shared/{language-server.DfMwkd2l.d.mts → language-server.BgDKnNok.d.mts} +45 -11
- package/dist/shared/language-server.Bmpq16Gw.d.ts +1338 -0
- package/dist/shared/language-server.C1ZfM22X.d.cts +1338 -0
- package/dist/shared/{language-server.U2piOAVt.d.cts → language-server.DJo88TnT.d.cts} +45 -11
- package/dist/shared/{language-server.DfjkvknB.cjs → language-server.DZRuJVSg.cjs} +209 -94
- package/dist/shared/{language-server.B8s2wfT_.cjs → language-server.N8HLDQqz.cjs} +137 -74
- package/dist/shared/{language-server.j-ShR6as.d.ts → language-server.PEjk7U9s.d.ts} +45 -11
- package/package.json +7 -7
- package/src/LikeC4FileSystem.ts +36 -0
- package/src/Rpc.ts +2 -2
- package/src/ast.ts +11 -3
- package/src/generated/ast.ts +112 -11
- package/src/generated/grammar.ts +1 -1
- package/src/index.ts +3 -3
- package/src/like-c4.langium +20 -1
- package/src/lsp/SemanticTokenProvider.ts +26 -8
- package/src/model/fqn-computation.ts +6 -2
- package/src/model/model-builder.ts +25 -30
- package/src/model/model-parser.ts +91 -18
- package/src/model-graph/LikeC4ModelGraph.ts +22 -11
- package/src/model-graph/compute-view/__test__/fixture.ts +69 -19
- package/src/model-graph/compute-view/compute.ts +85 -73
- package/src/model-graph/dynamic-view/compute.ts +12 -2
- package/src/model-graph/utils/applyCustomElementProperties.ts +1 -3
- package/src/model-graph/utils/applyViewRuleStyles.ts +0 -4
- package/src/references/scope-computation.ts +10 -0
- package/src/validation/index.ts +3 -0
- package/src/validation/specification.ts +21 -0
- package/src/view-utils/index.ts +0 -1
- package/src/view-utils/resolve-global-rules.ts +66 -50
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
const core = require('@likec4/core');
|
|
4
4
|
const remeda = require('remeda');
|
|
5
5
|
const dagre = require('@dagrejs/dagre');
|
|
6
|
+
const log = require('@likec4/log');
|
|
6
7
|
const objectHash = require('object-hash');
|
|
7
8
|
|
|
8
9
|
function _interopDefaultCompat (e) { return e && typeof e === 'object' && 'default' in e ? e.default : e; }
|
|
@@ -10,6 +11,51 @@ function _interopDefaultCompat (e) { return e && typeof e === 'object' && 'defau
|
|
|
10
11
|
const dagre__default = /*#__PURE__*/_interopDefaultCompat(dagre);
|
|
11
12
|
const objectHash__default = /*#__PURE__*/_interopDefaultCompat(objectHash);
|
|
12
13
|
|
|
14
|
+
function resolveGlobalRulesInElementView(view, globals) {
|
|
15
|
+
return view.rules.reduce((acc, rule) => {
|
|
16
|
+
if (core.isViewRuleGlobalPredicateRef(rule)) {
|
|
17
|
+
const globalPredicates = globals.predicates[rule.predicateId];
|
|
18
|
+
if (remeda.isNullish(globalPredicates)) {
|
|
19
|
+
log.logger.warn(`Global predicate not found: ${rule.predicateId}`);
|
|
20
|
+
return acc;
|
|
21
|
+
}
|
|
22
|
+
return acc.concat(globalPredicates);
|
|
23
|
+
}
|
|
24
|
+
if (core.isViewRuleGlobalStyle(rule)) {
|
|
25
|
+
const globalStyles = globals.styles[rule.styleId];
|
|
26
|
+
if (remeda.isNullish(globalStyles)) {
|
|
27
|
+
log.logger.warn(`Global style not found: ${rule.styleId}`);
|
|
28
|
+
return acc;
|
|
29
|
+
}
|
|
30
|
+
return acc.concat(globalStyles);
|
|
31
|
+
}
|
|
32
|
+
acc.push(rule);
|
|
33
|
+
return acc;
|
|
34
|
+
}, []);
|
|
35
|
+
}
|
|
36
|
+
function resolveGlobalRulesInDynamicView(view, globals) {
|
|
37
|
+
return view.rules.reduce((acc, rule) => {
|
|
38
|
+
if (core.isViewRuleGlobalPredicateRef(rule)) {
|
|
39
|
+
const globalPredicates = globals.dynamicPredicates[rule.predicateId];
|
|
40
|
+
if (remeda.isNullish(globalPredicates)) {
|
|
41
|
+
log.logger.warn(`Global predicate not found: ${rule.predicateId}`);
|
|
42
|
+
return acc;
|
|
43
|
+
}
|
|
44
|
+
return acc.concat(globalPredicates);
|
|
45
|
+
}
|
|
46
|
+
if (core.isViewRuleGlobalStyle(rule)) {
|
|
47
|
+
const globalStyles = globals.styles[rule.styleId];
|
|
48
|
+
if (remeda.isNullish(globalStyles)) {
|
|
49
|
+
log.logger.warn(`Global style not found: ${rule.styleId}`);
|
|
50
|
+
return acc;
|
|
51
|
+
}
|
|
52
|
+
return acc.concat(globalStyles);
|
|
53
|
+
}
|
|
54
|
+
acc.push(rule);
|
|
55
|
+
return acc;
|
|
56
|
+
}, []);
|
|
57
|
+
}
|
|
58
|
+
|
|
13
59
|
function calcViewLayoutHash(view) {
|
|
14
60
|
const tohash = {
|
|
15
61
|
id: view.id,
|
|
@@ -186,10 +232,6 @@ function applyViewRuleStyles(_rules, nodes) {
|
|
|
186
232
|
for (const rule of rules) {
|
|
187
233
|
const predicates = [];
|
|
188
234
|
for (const target of rule.targets) {
|
|
189
|
-
if (core.Expr.isWildcard(target)) {
|
|
190
|
-
predicates.push(() => true);
|
|
191
|
-
break;
|
|
192
|
-
}
|
|
193
235
|
predicates.push(elementExprToPredicate(target));
|
|
194
236
|
}
|
|
195
237
|
remeda.pipe(
|
|
@@ -929,6 +971,25 @@ class ComputeCtx {
|
|
|
929
971
|
get activeGroup() {
|
|
930
972
|
return this.activeGroupStack[0] ?? this.__rootGroup;
|
|
931
973
|
}
|
|
974
|
+
get includedElements() {
|
|
975
|
+
return /* @__PURE__ */ new Set([
|
|
976
|
+
...this.explicits,
|
|
977
|
+
...this.ctxEdges.flatMap((e) => [e.source, e.target])
|
|
978
|
+
]);
|
|
979
|
+
}
|
|
980
|
+
get resolvedElements() {
|
|
981
|
+
return /* @__PURE__ */ new Set([
|
|
982
|
+
...this.explicits,
|
|
983
|
+
...this.implicits,
|
|
984
|
+
...this.ctxEdges.flatMap((e) => [e.source, e.target])
|
|
985
|
+
]);
|
|
986
|
+
}
|
|
987
|
+
get edges() {
|
|
988
|
+
return this.ctxEdges;
|
|
989
|
+
}
|
|
990
|
+
get root() {
|
|
991
|
+
return core.isScopedElementView(this.view) ? this.view.viewOf : null;
|
|
992
|
+
}
|
|
932
993
|
static elementView(view, graph) {
|
|
933
994
|
return new ComputeCtx(view, graph).compute();
|
|
934
995
|
}
|
|
@@ -937,9 +998,11 @@ class ComputeCtx {
|
|
|
937
998
|
const {
|
|
938
999
|
docUri: _docUri,
|
|
939
1000
|
// exclude docUri
|
|
940
|
-
rules,
|
|
1001
|
+
rules: _rules,
|
|
1002
|
+
// exclude rules
|
|
941
1003
|
...view
|
|
942
1004
|
} = this.view;
|
|
1005
|
+
const rules = resolveGlobalRulesInElementView(this.view, this.graph.globals);
|
|
943
1006
|
const viewPredicates = rules.filter(remeda.anyPass([core.isViewRulePredicate, core.isViewRuleGroup]));
|
|
944
1007
|
if (this.root && viewPredicates.length == 0) {
|
|
945
1008
|
this.addElement(this.graph.element(this.root));
|
|
@@ -951,51 +1014,9 @@ class ComputeCtx {
|
|
|
951
1014
|
}
|
|
952
1015
|
const elements = [...this.includedElements];
|
|
953
1016
|
const nodesMap = buildComputeNodes(elements, this.groups);
|
|
954
|
-
const ancestorsOf = (node) => {
|
|
955
|
-
const ancestors = [];
|
|
956
|
-
let parent = node.parent;
|
|
957
|
-
while (parent) {
|
|
958
|
-
const parentNode = nodesMap.get(parent);
|
|
959
|
-
if (!parentNode) {
|
|
960
|
-
break;
|
|
961
|
-
}
|
|
962
|
-
ancestors.push(parentNode);
|
|
963
|
-
parent = parentNode.parent;
|
|
964
|
-
}
|
|
965
|
-
return ancestors;
|
|
966
|
-
};
|
|
967
|
-
const edgesMap = /* @__PURE__ */ new Map();
|
|
968
1017
|
const edges = this.computeEdges();
|
|
969
|
-
|
|
970
|
-
|
|
971
|
-
const source = nodesMap.get(edge.source);
|
|
972
|
-
const target = nodesMap.get(edge.target);
|
|
973
|
-
core.invariant(source, `Source node ${edge.source} not found`);
|
|
974
|
-
core.invariant(target, `Target node ${edge.target} not found`);
|
|
975
|
-
const sourceAncestors = ancestorsOf(source);
|
|
976
|
-
const targetAncestors = ancestorsOf(target);
|
|
977
|
-
const edgeParent = remeda.last(
|
|
978
|
-
core.commonHead(
|
|
979
|
-
remeda.reverse(sourceAncestors),
|
|
980
|
-
remeda.reverse(targetAncestors)
|
|
981
|
-
)
|
|
982
|
-
);
|
|
983
|
-
edge.parent = edgeParent?.id ?? null;
|
|
984
|
-
source.outEdges.push(edge.id);
|
|
985
|
-
target.inEdges.push(edge.id);
|
|
986
|
-
for (const sourceAncestor of sourceAncestors) {
|
|
987
|
-
if (sourceAncestor === edgeParent) {
|
|
988
|
-
break;
|
|
989
|
-
}
|
|
990
|
-
sourceAncestor.outEdges.push(edge.id);
|
|
991
|
-
}
|
|
992
|
-
for (const targetAncestor of targetAncestors) {
|
|
993
|
-
if (targetAncestor === edgeParent) {
|
|
994
|
-
break;
|
|
995
|
-
}
|
|
996
|
-
targetAncestor.inEdges.push(edge.id);
|
|
997
|
-
}
|
|
998
|
-
}
|
|
1018
|
+
const edgesMap = new Map(edges.map((edge) => [edge.id, edge]));
|
|
1019
|
+
this.linkNodesAndEdges(nodesMap, edges);
|
|
999
1020
|
let initialSort = elements.map((e) => core.nonNullable(nodesMap.get(e.id), `Node ${e.id} not found in nodesMap`));
|
|
1000
1021
|
if (this.groups.length > 0) {
|
|
1001
1022
|
initialSort = remeda.concat(
|
|
@@ -1027,7 +1048,13 @@ class ComputeCtx {
|
|
|
1027
1048
|
...autoLayoutRule?.nodeSep && { nodeSep: autoLayoutRule.nodeSep },
|
|
1028
1049
|
...autoLayoutRule?.rankSep && { rankSep: autoLayoutRule.rankSep }
|
|
1029
1050
|
},
|
|
1030
|
-
nodes: remeda.map(nodes,
|
|
1051
|
+
nodes: remeda.map(nodes, (n) => {
|
|
1052
|
+
delete n.notation;
|
|
1053
|
+
if (n.icon === "none") {
|
|
1054
|
+
delete n.icon;
|
|
1055
|
+
}
|
|
1056
|
+
return n;
|
|
1057
|
+
}),
|
|
1031
1058
|
edges: applyCustomRelationProperties(rules, nodes, sortedEdges),
|
|
1032
1059
|
...elementNotations.length > 0 && {
|
|
1033
1060
|
notation: {
|
|
@@ -1036,9 +1063,6 @@ class ComputeCtx {
|
|
|
1036
1063
|
}
|
|
1037
1064
|
});
|
|
1038
1065
|
}
|
|
1039
|
-
get root() {
|
|
1040
|
-
return core.isScopedElementView(this.view) ? this.view.viewOf : null;
|
|
1041
|
-
}
|
|
1042
1066
|
computeEdges() {
|
|
1043
1067
|
return this.ctxEdges.map((e) => {
|
|
1044
1068
|
core.invariant(remeda.hasAtLeast(e.relations, 1), "Edge must have at least one relation");
|
|
@@ -1131,21 +1155,36 @@ class ComputeCtx {
|
|
|
1131
1155
|
);
|
|
1132
1156
|
});
|
|
1133
1157
|
}
|
|
1134
|
-
|
|
1135
|
-
|
|
1136
|
-
|
|
1137
|
-
|
|
1138
|
-
|
|
1139
|
-
|
|
1140
|
-
|
|
1141
|
-
|
|
1142
|
-
|
|
1143
|
-
|
|
1144
|
-
|
|
1145
|
-
|
|
1146
|
-
|
|
1147
|
-
|
|
1148
|
-
|
|
1158
|
+
linkNodesAndEdges(nodesMap, edges) {
|
|
1159
|
+
for (const edge of edges) {
|
|
1160
|
+
const source = nodesMap.get(edge.source);
|
|
1161
|
+
const target = nodesMap.get(edge.target);
|
|
1162
|
+
core.invariant(source, `Source node ${edge.source} not found`);
|
|
1163
|
+
core.invariant(target, `Target node ${edge.target} not found`);
|
|
1164
|
+
const sourceAncestors = this.ancestorsOf(source, nodesMap);
|
|
1165
|
+
const targetAncestors = this.ancestorsOf(target, nodesMap);
|
|
1166
|
+
const edgeParent = remeda.last(
|
|
1167
|
+
core.commonHead(
|
|
1168
|
+
remeda.reverse(sourceAncestors),
|
|
1169
|
+
remeda.reverse(targetAncestors)
|
|
1170
|
+
)
|
|
1171
|
+
);
|
|
1172
|
+
edge.parent = edgeParent?.id ?? null;
|
|
1173
|
+
source.outEdges.push(edge.id);
|
|
1174
|
+
target.inEdges.push(edge.id);
|
|
1175
|
+
for (const sourceAncestor of sourceAncestors) {
|
|
1176
|
+
if (sourceAncestor === edgeParent) {
|
|
1177
|
+
break;
|
|
1178
|
+
}
|
|
1179
|
+
sourceAncestor.outEdges.push(edge.id);
|
|
1180
|
+
}
|
|
1181
|
+
for (const targetAncestor of targetAncestors) {
|
|
1182
|
+
if (targetAncestor === edgeParent) {
|
|
1183
|
+
break;
|
|
1184
|
+
}
|
|
1185
|
+
targetAncestor.inEdges.push(edge.id);
|
|
1186
|
+
}
|
|
1187
|
+
}
|
|
1149
1188
|
}
|
|
1150
1189
|
addEdges(edges) {
|
|
1151
1190
|
const added = [];
|
|
@@ -1234,9 +1273,6 @@ class ComputeCtx {
|
|
|
1234
1273
|
}),
|
|
1235
1274
|
remeda.filter(remeda.isNonNull)
|
|
1236
1275
|
);
|
|
1237
|
-
if (excludedImplicits.size === 0) {
|
|
1238
|
-
return;
|
|
1239
|
-
}
|
|
1240
1276
|
this.ctxEdges = ctxEdges;
|
|
1241
1277
|
const remaining = this.includedElements;
|
|
1242
1278
|
if (remaining.size === 0) {
|
|
@@ -1413,6 +1449,19 @@ class ComputeCtx {
|
|
|
1413
1449
|
}
|
|
1414
1450
|
core.nonexhaustive(expr);
|
|
1415
1451
|
}
|
|
1452
|
+
ancestorsOf(node, nodesMap) {
|
|
1453
|
+
const ancestors = [];
|
|
1454
|
+
let parent = node.parent;
|
|
1455
|
+
while (parent) {
|
|
1456
|
+
const parentNode = nodesMap.get(parent);
|
|
1457
|
+
if (!parentNode) {
|
|
1458
|
+
break;
|
|
1459
|
+
}
|
|
1460
|
+
ancestors.push(parentNode);
|
|
1461
|
+
parent = parentNode.parent;
|
|
1462
|
+
}
|
|
1463
|
+
return ancestors;
|
|
1464
|
+
}
|
|
1416
1465
|
getEdgeLabel(relation) {
|
|
1417
1466
|
const labelParts = [];
|
|
1418
1467
|
if (remeda.isTruthy(relation.title)) {
|
|
@@ -1490,7 +1539,8 @@ class DynamicViewComputeCtx {
|
|
|
1490
1539
|
const {
|
|
1491
1540
|
docUri: _docUri,
|
|
1492
1541
|
// exclude docUri
|
|
1493
|
-
rules,
|
|
1542
|
+
rules: _rules,
|
|
1543
|
+
// exclude rules
|
|
1494
1544
|
steps: viewSteps,
|
|
1495
1545
|
...view
|
|
1496
1546
|
} = this.view;
|
|
@@ -1510,6 +1560,7 @@ class DynamicViewComputeCtx {
|
|
|
1510
1560
|
}
|
|
1511
1561
|
stepNum++;
|
|
1512
1562
|
}
|
|
1563
|
+
const rules = resolveGlobalRulesInDynamicView(this.view, this.graph.globals);
|
|
1513
1564
|
for (const rule of rules) {
|
|
1514
1565
|
if (core.isDynamicViewIncludeRule(rule)) {
|
|
1515
1566
|
for (const expr of rule.include) {
|
|
@@ -1573,7 +1624,13 @@ class DynamicViewComputeCtx {
|
|
|
1573
1624
|
...autoLayoutRule?.nodeSep && { nodeSep: autoLayoutRule.nodeSep },
|
|
1574
1625
|
...autoLayoutRule?.rankSep && { rankSep: autoLayoutRule.rankSep }
|
|
1575
1626
|
},
|
|
1576
|
-
nodes: remeda.map(nodes,
|
|
1627
|
+
nodes: remeda.map(nodes, (n) => {
|
|
1628
|
+
delete n.notation;
|
|
1629
|
+
if (n.icon === "none") {
|
|
1630
|
+
delete n.icon;
|
|
1631
|
+
}
|
|
1632
|
+
return n;
|
|
1633
|
+
}),
|
|
1577
1634
|
edges,
|
|
1578
1635
|
...elementNotations.length > 0 && {
|
|
1579
1636
|
notation: {
|
|
@@ -1663,7 +1720,13 @@ class LikeC4ModelGraph {
|
|
|
1663
1720
|
// Relationships inside the element, among descendants
|
|
1664
1721
|
#internal = new MapRelations();
|
|
1665
1722
|
#cacheAscendingSiblings = /* @__PURE__ */ new Map();
|
|
1666
|
-
|
|
1723
|
+
globals;
|
|
1724
|
+
constructor({ elements, relations, globals }) {
|
|
1725
|
+
this.globals = globals ?? {
|
|
1726
|
+
predicates: {},
|
|
1727
|
+
dynamicPredicates: {},
|
|
1728
|
+
styles: {}
|
|
1729
|
+
};
|
|
1667
1730
|
for (const el of Object.values(elements)) {
|
|
1668
1731
|
this.addElement(el);
|
|
1669
1732
|
}
|
|
@@ -47,7 +47,7 @@ type ArrowType = 'crow' | 'diamond' | 'dot' | 'none' | 'normal' | 'odiamond' | '
|
|
|
47
47
|
type BorderStyleValue = 'none' | LineOptions;
|
|
48
48
|
type CustomColorId = 'element' | 'model' | ArrowType | ElementShape | LineOptions | string;
|
|
49
49
|
type CustomColorValue = string;
|
|
50
|
-
type DynamicViewRule = DynamicViewIncludePredicate | ViewRuleAutoLayout | ViewRuleStyleOrGlobalRef;
|
|
50
|
+
type DynamicViewRule = DynamicViewGlobalPredicateRef | DynamicViewIncludePredicate | ViewRuleAutoLayout | ViewRuleStyleOrGlobalRef;
|
|
51
51
|
declare const DynamicViewRule = "DynamicViewRule";
|
|
52
52
|
declare function isDynamicViewRule(item: unknown): item is DynamicViewRule;
|
|
53
53
|
type ElementExpression = ElementDescedantsExpression | ElementKindExpression | ElementRef | ElementTagExpression | ExpandElementExpression | WildcardExpression;
|
|
@@ -94,7 +94,7 @@ type ViewLayoutDirection = 'BottomTop' | 'LeftRight' | 'RightLeft' | 'TopBottom'
|
|
|
94
94
|
type ViewProperty = LinkProperty | ViewStringProperty;
|
|
95
95
|
declare const ViewProperty = "ViewProperty";
|
|
96
96
|
declare function isViewProperty(item: unknown): item is ViewProperty;
|
|
97
|
-
type ViewRule = ViewRuleAutoLayout | ViewRuleGroup | ViewRulePredicate | ViewRuleStyleOrGlobalRef;
|
|
97
|
+
type ViewRule = ViewRuleAutoLayout | ViewRuleGlobalPredicateRef | ViewRuleGroup | ViewRulePredicate | ViewRuleStyleOrGlobalRef;
|
|
98
98
|
declare const ViewRule = "ViewRule";
|
|
99
99
|
declare function isViewRule(item: unknown): item is ViewRule;
|
|
100
100
|
type ViewRulePredicate = ExcludePredicate | IncludePredicate;
|
|
@@ -179,8 +179,14 @@ interface DynamicViewBody extends AstNode {
|
|
|
179
179
|
}
|
|
180
180
|
declare const DynamicViewBody = "DynamicViewBody";
|
|
181
181
|
declare function isDynamicViewBody(item: unknown): item is DynamicViewBody;
|
|
182
|
-
interface
|
|
182
|
+
interface DynamicViewGlobalPredicateRef extends AstNode {
|
|
183
183
|
readonly $container: DynamicViewBody;
|
|
184
|
+
readonly $type: 'DynamicViewGlobalPredicateRef';
|
|
185
|
+
predicate: Reference<GlobalDynamicPredicateGroup>;
|
|
186
|
+
}
|
|
187
|
+
declare const DynamicViewGlobalPredicateRef = "DynamicViewGlobalPredicateRef";
|
|
188
|
+
interface DynamicViewIncludePredicate extends AstNode {
|
|
189
|
+
readonly $container: DynamicViewBody | GlobalDynamicPredicateGroup;
|
|
184
190
|
readonly $type: 'DynamicViewIncludePredicate';
|
|
185
191
|
predicates: DynamicViewPredicateIterator;
|
|
186
192
|
}
|
|
@@ -331,7 +337,7 @@ interface ElementViewRef extends AstNode {
|
|
|
331
337
|
}
|
|
332
338
|
declare const ElementViewRef = "ElementViewRef";
|
|
333
339
|
interface ExcludePredicate extends AstNode {
|
|
334
|
-
readonly $container: ElementViewBody | ViewRuleGroup;
|
|
340
|
+
readonly $container: ElementViewBody | GlobalPredicateGroup | ViewRuleGroup;
|
|
335
341
|
readonly $type: 'ExcludePredicate';
|
|
336
342
|
predicates: Predicates;
|
|
337
343
|
}
|
|
@@ -364,10 +370,27 @@ interface FqnElementRef extends AstNode {
|
|
|
364
370
|
parent?: FqnElementRef;
|
|
365
371
|
}
|
|
366
372
|
declare const FqnElementRef = "FqnElementRef";
|
|
373
|
+
interface GlobalDynamicPredicateGroup extends AstNode {
|
|
374
|
+
readonly $container: Globals;
|
|
375
|
+
readonly $type: 'GlobalDynamicPredicateGroup';
|
|
376
|
+
name: string;
|
|
377
|
+
predicates: Array<DynamicViewIncludePredicate>;
|
|
378
|
+
}
|
|
379
|
+
declare const GlobalDynamicPredicateGroup = "GlobalDynamicPredicateGroup";
|
|
380
|
+
declare function isGlobalDynamicPredicateGroup(item: unknown): item is GlobalDynamicPredicateGroup;
|
|
381
|
+
interface GlobalPredicateGroup extends AstNode {
|
|
382
|
+
readonly $container: Globals;
|
|
383
|
+
readonly $type: 'GlobalPredicateGroup';
|
|
384
|
+
name: string;
|
|
385
|
+
predicates: Array<ViewRulePredicate>;
|
|
386
|
+
}
|
|
387
|
+
declare const GlobalPredicateGroup = "GlobalPredicateGroup";
|
|
388
|
+
declare function isGlobalPredicateGroup(item: unknown): item is GlobalPredicateGroup;
|
|
367
389
|
interface Globals extends AstNode {
|
|
368
390
|
readonly $container: LikeC4Grammar;
|
|
369
391
|
readonly $type: 'Globals';
|
|
370
392
|
name: 'global';
|
|
393
|
+
predicates: Array<GlobalDynamicPredicateGroup | GlobalPredicateGroup>;
|
|
371
394
|
styles: Array<GlobalStyle | GlobalStyleGroup>;
|
|
372
395
|
}
|
|
373
396
|
declare const Globals = "Globals";
|
|
@@ -400,11 +423,11 @@ interface IconProperty extends AstNode {
|
|
|
400
423
|
readonly $type: 'IconProperty';
|
|
401
424
|
key: 'icon';
|
|
402
425
|
libicon?: Reference<LibIcon>;
|
|
403
|
-
value?: Uri;
|
|
426
|
+
value?: 'none' | Uri;
|
|
404
427
|
}
|
|
405
428
|
declare const IconProperty = "IconProperty";
|
|
406
429
|
interface IncludePredicate extends AstNode {
|
|
407
|
-
readonly $container: ElementViewBody | ViewRuleGroup;
|
|
430
|
+
readonly $container: ElementViewBody | GlobalPredicateGroup | ViewRuleGroup;
|
|
408
431
|
readonly $type: 'IncludePredicate';
|
|
409
432
|
predicates: Predicates;
|
|
410
433
|
}
|
|
@@ -684,6 +707,12 @@ interface ViewRuleAutoLayout extends AstNode {
|
|
|
684
707
|
rankSep?: number;
|
|
685
708
|
}
|
|
686
709
|
declare const ViewRuleAutoLayout = "ViewRuleAutoLayout";
|
|
710
|
+
interface ViewRuleGlobalPredicateRef extends AstNode {
|
|
711
|
+
readonly $container: ElementViewBody;
|
|
712
|
+
readonly $type: 'ViewRuleGlobalPredicateRef';
|
|
713
|
+
predicate: Reference<GlobalPredicateGroup>;
|
|
714
|
+
}
|
|
715
|
+
declare const ViewRuleGlobalPredicateRef = "ViewRuleGlobalPredicateRef";
|
|
687
716
|
interface ViewRuleGlobalStyle extends AstNode {
|
|
688
717
|
readonly $container: DynamicViewBody | ElementViewBody | ModelViews;
|
|
689
718
|
readonly $type: 'ViewRuleGlobalStyle';
|
|
@@ -780,6 +809,7 @@ type LikeC4AstType = {
|
|
|
780
809
|
DirectedRelationExpression: DirectedRelationExpression;
|
|
781
810
|
DynamicView: DynamicView;
|
|
782
811
|
DynamicViewBody: DynamicViewBody;
|
|
812
|
+
DynamicViewGlobalPredicateRef: DynamicViewGlobalPredicateRef;
|
|
783
813
|
DynamicViewIncludePredicate: DynamicViewIncludePredicate;
|
|
784
814
|
DynamicViewParallelSteps: DynamicViewParallelSteps;
|
|
785
815
|
DynamicViewPredicateIterator: DynamicViewPredicateIterator;
|
|
@@ -810,6 +840,8 @@ type LikeC4AstType = {
|
|
|
810
840
|
ExtendElement: ExtendElement;
|
|
811
841
|
ExtendElementBody: ExtendElementBody;
|
|
812
842
|
FqnElementRef: FqnElementRef;
|
|
843
|
+
GlobalDynamicPredicateGroup: GlobalDynamicPredicateGroup;
|
|
844
|
+
GlobalPredicateGroup: GlobalPredicateGroup;
|
|
813
845
|
GlobalStyle: GlobalStyle;
|
|
814
846
|
GlobalStyleGroup: GlobalStyleGroup;
|
|
815
847
|
GlobalStyleId: GlobalStyleId;
|
|
@@ -865,6 +897,7 @@ type LikeC4AstType = {
|
|
|
865
897
|
ViewRef: ViewRef;
|
|
866
898
|
ViewRule: ViewRule;
|
|
867
899
|
ViewRuleAutoLayout: ViewRuleAutoLayout;
|
|
900
|
+
ViewRuleGlobalPredicateRef: ViewRuleGlobalPredicateRef;
|
|
868
901
|
ViewRuleGlobalStyle: ViewRuleGlobalStyle;
|
|
869
902
|
ViewRuleGroup: ViewRuleGroup;
|
|
870
903
|
ViewRulePredicate: ViewRulePredicate;
|
|
@@ -960,9 +993,7 @@ interface ParsedAstRelation {
|
|
|
960
993
|
[key: string]: string;
|
|
961
994
|
};
|
|
962
995
|
}
|
|
963
|
-
|
|
964
|
-
styles: Record<c4.GlobalStyleID, c4.NonEmptyArray<c4.ViewRuleStyle>>;
|
|
965
|
-
}
|
|
996
|
+
type ParsedAstGlobals = c4.ModelGlobals;
|
|
966
997
|
interface ParsedAstElementView {
|
|
967
998
|
__: 'element';
|
|
968
999
|
id: c4.ViewID;
|
|
@@ -1015,7 +1046,7 @@ interface ParsedLikeC4LangiumDocument extends Omit<LangiumDocument<LikeC4Grammar
|
|
|
1015
1046
|
}
|
|
1016
1047
|
type Guard<N extends AstNode> = (n: AstNode) => n is N;
|
|
1017
1048
|
type Guarded<G> = G extends Guard<infer N> ? N : never;
|
|
1018
|
-
declare const isValidatableAstNode: (n: AstNode) => n is Guarded<typeof isLikeC4View | typeof isRelation | typeof isExtendElement | typeof isElement | typeof isGlobals | typeof isGlobalStyle | typeof isGlobalStyleGroup | typeof isDynamicViewPredicateIterator | typeof isElementPredicateWith | typeof isRelationPredicateWith | typeof isElementExpression | typeof isRelationExpression | typeof isDynamicViewParallelSteps | typeof isDynamicViewStep | typeof isViewProperty | typeof isStyleProperty | typeof isTags | typeof isViewRule | typeof isDynamicViewRule | typeof isElementViewBody | typeof isDynamicViewBody | typeof isRelationProperty | typeof isRelationBody | typeof isElementProperty | typeof isElementBody | typeof isExtendElementBody | typeof isSpecificationElementKind | typeof isSpecificationRelationshipKind | typeof isSpecificationTag | typeof isSpecificationColor | typeof isSpecificationRule | typeof isModelViews | typeof isModel>;
|
|
1049
|
+
declare const isValidatableAstNode: (n: AstNode) => n is Guarded<typeof isLikeC4View | typeof isRelation | typeof isExtendElement | typeof isElement | typeof isGlobals | typeof isGlobalPredicateGroup | typeof isGlobalDynamicPredicateGroup | typeof isGlobalStyle | typeof isGlobalStyleGroup | typeof isDynamicViewPredicateIterator | typeof isElementPredicateWith | typeof isRelationPredicateWith | typeof isElementExpression | typeof isRelationExpression | typeof isDynamicViewParallelSteps | typeof isDynamicViewStep | typeof isViewProperty | typeof isStyleProperty | typeof isTags | typeof isViewRule | typeof isDynamicViewRule | typeof isElementViewBody | typeof isDynamicViewBody | typeof isRelationProperty | typeof isRelationBody | typeof isElementProperty | typeof isElementBody | typeof isExtendElementBody | typeof isSpecificationElementKind | typeof isSpecificationRelationshipKind | typeof isSpecificationTag | typeof isSpecificationColor | typeof isSpecificationRule | typeof isModelViews | typeof isModel>;
|
|
1019
1050
|
type ValidatableAstNode = Guarded<typeof isValidatableAstNode>;
|
|
1020
1051
|
declare function checksFromDiagnostics(doc: LikeC4LangiumDocument): {
|
|
1021
1052
|
isValid: (n: ValidatableAstNode) => boolean;
|
|
@@ -1135,8 +1166,10 @@ declare class LikeC4ModelParser {
|
|
|
1135
1166
|
private parseElement;
|
|
1136
1167
|
private parseRelation;
|
|
1137
1168
|
private parseGlobal;
|
|
1169
|
+
private parseAndStoreGlobalPredicateGroupOrDynamic;
|
|
1170
|
+
private parseGlobalPredicateGroup;
|
|
1171
|
+
private parseGlobalDynamicPredicateGroup;
|
|
1138
1172
|
private parseGlobalStyleOrGroup;
|
|
1139
|
-
private parseGlobalStyle;
|
|
1140
1173
|
private parseViews;
|
|
1141
1174
|
private parseViewRulePredicate;
|
|
1142
1175
|
private parsePredicate;
|
|
@@ -1150,6 +1183,7 @@ declare class LikeC4ModelParser {
|
|
|
1150
1183
|
private parseRelationPredicateWith;
|
|
1151
1184
|
private parseRelationExpr;
|
|
1152
1185
|
private parseViewRule;
|
|
1186
|
+
private parseViewRuleGlobalPredicateRef;
|
|
1153
1187
|
private parseViewRuleStyleOrGlobalRef;
|
|
1154
1188
|
private parseViewRuleStyle;
|
|
1155
1189
|
private parseViewRuleGroup;
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@likec4/language-server",
|
|
3
3
|
"description": "LikeC4 Language Server",
|
|
4
|
-
"version": "1.
|
|
4
|
+
"version": "1.17.0",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"bugs": "https://github.com/likec4/likec4/issues",
|
|
7
7
|
"homepage": "https://likec4.dev",
|
|
@@ -112,8 +112,8 @@
|
|
|
112
112
|
},
|
|
113
113
|
"dependencies": {
|
|
114
114
|
"@dagrejs/dagre": "^1.1.4",
|
|
115
|
-
"@likec4/core": "1.
|
|
116
|
-
"@likec4/log": "1.
|
|
115
|
+
"@likec4/core": "1.17.0",
|
|
116
|
+
"@likec4/log": "1.17.0",
|
|
117
117
|
"@msgpack/msgpack": "^3.0.0-beta2",
|
|
118
118
|
"@smithy/util-base64": "^3.0.0",
|
|
119
119
|
"fast-equals": "^5.0.1",
|
|
@@ -133,12 +133,12 @@
|
|
|
133
133
|
"vscode-uri": "3.0.8"
|
|
134
134
|
},
|
|
135
135
|
"devDependencies": {
|
|
136
|
-
"@likec4/icons": "1.
|
|
137
|
-
"@likec4/tsconfig": "1.
|
|
136
|
+
"@likec4/icons": "1.17.0",
|
|
137
|
+
"@likec4/tsconfig": "1.17.0",
|
|
138
138
|
"@types/node": "^20.16.14",
|
|
139
139
|
"@types/object-hash": "^3.0.6",
|
|
140
140
|
"@types/string-hash": "^1.1.3",
|
|
141
|
-
"@vitest/coverage-v8": "^2.1.
|
|
141
|
+
"@vitest/coverage-v8": "^2.1.5",
|
|
142
142
|
"execa": "^9.3.1",
|
|
143
143
|
"langium-cli": "3.2.0",
|
|
144
144
|
"npm-run-all2": "^6.2.6",
|
|
@@ -146,7 +146,7 @@
|
|
|
146
146
|
"turbo": "^2.2.3",
|
|
147
147
|
"typescript": "^5.6.3",
|
|
148
148
|
"unbuild": "^3.0.0-rc.11",
|
|
149
|
-
"vitest": "^2.1.
|
|
149
|
+
"vitest": "^2.1.5"
|
|
150
150
|
},
|
|
151
151
|
"packageManager": "yarn@4.5.1"
|
|
152
152
|
}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { type FileSystemNode, URI, UriUtils } from 'langium'
|
|
2
|
+
import { NodeFileSystemProvider } from 'langium/node'
|
|
3
|
+
import { lstatSync, readlinkSync } from 'node:fs'
|
|
4
|
+
import { readdir } from 'node:fs/promises'
|
|
5
|
+
import { dirname, resolve } from 'node:path'
|
|
6
|
+
|
|
7
|
+
export const LikeC4FileSystem = {
|
|
8
|
+
fileSystemProvider: () => new SymLinkTraversingFileSystemProvider()
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* A file system provider that follows symbolic links.
|
|
13
|
+
* @see https://github.com/likec4/likec4/pull/1213
|
|
14
|
+
*/
|
|
15
|
+
class SymLinkTraversingFileSystemProvider extends NodeFileSystemProvider {
|
|
16
|
+
override async readDirectory(folderPath: URI): Promise<FileSystemNode[]> {
|
|
17
|
+
const dirents = await readdir(folderPath.fsPath, { withFileTypes: true })
|
|
18
|
+
return dirents.map(dirent => (this.followUri(UriUtils.joinPath(folderPath, dirent.name))))
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
followUri(uri: URI): FileSystemNode {
|
|
22
|
+
const directoryPath = dirname(uri.fsPath)
|
|
23
|
+
const stat = lstatSync(uri.fsPath)
|
|
24
|
+
if (stat.isSymbolicLink()) {
|
|
25
|
+
const resolved_link = readlinkSync(uri.fsPath)
|
|
26
|
+
const linked_path = resolve(directoryPath, resolved_link)
|
|
27
|
+
return this.followUri(URI.file(linked_path))
|
|
28
|
+
} else {
|
|
29
|
+
return {
|
|
30
|
+
isFile: stat.isFile(),
|
|
31
|
+
isDirectory: stat.isDirectory(),
|
|
32
|
+
uri
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
}
|
package/src/Rpc.ts
CHANGED
package/src/ast.ts
CHANGED
|
@@ -93,9 +93,13 @@ export interface ParsedAstRelation {
|
|
|
93
93
|
metadata?: { [key: string]: string }
|
|
94
94
|
}
|
|
95
95
|
|
|
96
|
-
export interface ParsedAstGlobals {
|
|
97
|
-
|
|
98
|
-
|
|
96
|
+
// export interface ParsedAstGlobals {
|
|
97
|
+
// predicates: Record<c4.GlobalElRelID, c4.NonEmptyArray<c4.ViewRulePredicate>>
|
|
98
|
+
// dynamicPredicates: Record<c4.GlobalElRelID, c4.NonEmptyArray<c4.DynamicViewIncludeRule>>
|
|
99
|
+
// styles: Record<c4.GlobalStyleID, c4.NonEmptyArray<c4.ViewRuleStyle>>
|
|
100
|
+
// }
|
|
101
|
+
// Alias for refactoring
|
|
102
|
+
export type ParsedAstGlobals = c4.ModelGlobals
|
|
99
103
|
|
|
100
104
|
export interface ParsedAstElementView {
|
|
101
105
|
__: 'element'
|
|
@@ -196,6 +200,8 @@ export function cleanParsedModel(doc: LikeC4LangiumDocument) {
|
|
|
196
200
|
c4Elements: [],
|
|
197
201
|
c4Relations: [],
|
|
198
202
|
c4Globals: {
|
|
203
|
+
predicates: {},
|
|
204
|
+
dynamicPredicates: {},
|
|
199
205
|
styles: {}
|
|
200
206
|
},
|
|
201
207
|
c4Views: []
|
|
@@ -235,6 +241,8 @@ function validatableAstNodeGuards<const Predicates extends Guard<AstNode>[]>(
|
|
|
235
241
|
}
|
|
236
242
|
const isValidatableAstNode = validatableAstNodeGuards([
|
|
237
243
|
ast.isGlobals,
|
|
244
|
+
ast.isGlobalPredicateGroup,
|
|
245
|
+
ast.isGlobalDynamicPredicateGroup,
|
|
238
246
|
ast.isGlobalStyle,
|
|
239
247
|
ast.isGlobalStyleGroup,
|
|
240
248
|
ast.isDynamicViewPredicateIterator,
|