@likec4/language-server 1.15.0 → 1.16.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 +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 +2 -2
- 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.7iILaJYc.d.ts +1338 -0
- package/dist/shared/{language-server.80ITEDo5.cjs → language-server.Bd3NZ8uH.cjs} +130 -76
- package/dist/shared/{language-server.DXC9g4_f.mjs → language-server.C5gxpVUH.mjs} +132 -78
- package/dist/shared/language-server.CmBZHwSl.d.cts +1338 -0
- package/dist/shared/{language-server.U2piOAVt.d.cts → language-server.CnkCWVtf.d.cts} +44 -10
- package/dist/shared/{language-server.DfMwkd2l.d.mts → language-server.DIaiY0-C.d.mts} +44 -10
- package/dist/shared/language-server.DViE1Zxi.d.mts +1338 -0
- package/dist/shared/{language-server.zY53FGJE.mjs → language-server.D_13fWJQ.mjs} +216 -94
- package/dist/shared/{language-server.j-ShR6as.d.ts → language-server.DwyQ1FtY.d.ts} +44 -10
- package/dist/shared/{language-server.BUtiWTKg.cjs → language-server.Dym6GL4P.cjs} +214 -92
- package/package.json +8 -8
- package/src/ast.ts +11 -3
- package/src/formatting/LikeC4Formatter.ts +44 -4
- package/src/generated/ast.ts +111 -10
- package/src/generated/grammar.ts +1 -1
- package/src/like-c4.langium +19 -0
- package/src/lsp/SemanticTokenProvider.ts +3 -1
- package/src/model/model-builder.ts +34 -32
- 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 +114 -44
- package/src/model-graph/compute-view/compute.ts +77 -72
- package/src/model-graph/dynamic-view/compute.ts +4 -1
- package/src/model-graph/utils/applyCustomRelationProperties.ts +7 -38
- package/src/model-graph/utils/applyViewRuleStyles.ts +0 -4
- package/src/model-graph/utils/relationExpressionToPredicates.ts +43 -0
- 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,
|
|
@@ -121,7 +167,9 @@ function applyCustomElementProperties(_rules, _nodes) {
|
|
|
121
167
|
function relationExpressionToPredicates(expr) {
|
|
122
168
|
switch (true) {
|
|
123
169
|
case core.Expr.isRelationWhere(expr):
|
|
124
|
-
|
|
170
|
+
const predicate = relationExpressionToPredicates(expr.where.expr);
|
|
171
|
+
const where = core.whereOperatorAsPredicate(expr.where.condition);
|
|
172
|
+
return (e) => predicate(e) && where(e);
|
|
125
173
|
case core.Expr.isRelation(expr): {
|
|
126
174
|
const isSource = elementExprToPredicate(expr.source);
|
|
127
175
|
const isTarget = elementExprToPredicate(expr.target);
|
|
@@ -145,6 +193,7 @@ function relationExpressionToPredicates(expr) {
|
|
|
145
193
|
core.nonexhaustive(expr);
|
|
146
194
|
}
|
|
147
195
|
}
|
|
196
|
+
|
|
148
197
|
function applyCustomRelationProperties(_rules, nodes, _edges) {
|
|
149
198
|
const rules = _rules.flatMap(flattenGroupRules(core.Expr.isCustomRelationExpr));
|
|
150
199
|
const edges = Array.from(_edges);
|
|
@@ -162,12 +211,12 @@ function applyCustomRelationProperties(_rules, nodes, _edges) {
|
|
|
162
211
|
if (!source || !target) {
|
|
163
212
|
return;
|
|
164
213
|
}
|
|
165
|
-
if (satisfies({ source, target })) {
|
|
214
|
+
if (satisfies({ source, target, ...remeda.pick(edge, ["kind", "tags"]) })) {
|
|
166
215
|
edges[i] = {
|
|
167
216
|
...edge,
|
|
217
|
+
...props,
|
|
168
218
|
label: title ?? edge.label,
|
|
169
|
-
isCustomized: true
|
|
170
|
-
...props
|
|
219
|
+
isCustomized: true
|
|
171
220
|
};
|
|
172
221
|
}
|
|
173
222
|
});
|
|
@@ -183,10 +232,6 @@ function applyViewRuleStyles(_rules, nodes) {
|
|
|
183
232
|
for (const rule of rules) {
|
|
184
233
|
const predicates = [];
|
|
185
234
|
for (const target of rule.targets) {
|
|
186
|
-
if (core.Expr.isWildcard(target)) {
|
|
187
|
-
predicates.push(() => true);
|
|
188
|
-
break;
|
|
189
|
-
}
|
|
190
235
|
predicates.push(elementExprToPredicate(target));
|
|
191
236
|
}
|
|
192
237
|
remeda.pipe(
|
|
@@ -926,6 +971,25 @@ class ComputeCtx {
|
|
|
926
971
|
get activeGroup() {
|
|
927
972
|
return this.activeGroupStack[0] ?? this.__rootGroup;
|
|
928
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
|
+
}
|
|
929
993
|
static elementView(view, graph) {
|
|
930
994
|
return new ComputeCtx(view, graph).compute();
|
|
931
995
|
}
|
|
@@ -934,9 +998,11 @@ class ComputeCtx {
|
|
|
934
998
|
const {
|
|
935
999
|
docUri: _docUri,
|
|
936
1000
|
// exclude docUri
|
|
937
|
-
rules,
|
|
1001
|
+
rules: _rules,
|
|
1002
|
+
// exclude rules
|
|
938
1003
|
...view
|
|
939
1004
|
} = this.view;
|
|
1005
|
+
const rules = resolveGlobalRulesInElementView(this.view, this.graph.globals);
|
|
940
1006
|
const viewPredicates = rules.filter(remeda.anyPass([core.isViewRulePredicate, core.isViewRuleGroup]));
|
|
941
1007
|
if (this.root && viewPredicates.length == 0) {
|
|
942
1008
|
this.addElement(this.graph.element(this.root));
|
|
@@ -948,51 +1014,9 @@ class ComputeCtx {
|
|
|
948
1014
|
}
|
|
949
1015
|
const elements = [...this.includedElements];
|
|
950
1016
|
const nodesMap = buildComputeNodes(elements, this.groups);
|
|
951
|
-
const ancestorsOf = (node) => {
|
|
952
|
-
const ancestors = [];
|
|
953
|
-
let parent = node.parent;
|
|
954
|
-
while (parent) {
|
|
955
|
-
const parentNode = nodesMap.get(parent);
|
|
956
|
-
if (!parentNode) {
|
|
957
|
-
break;
|
|
958
|
-
}
|
|
959
|
-
ancestors.push(parentNode);
|
|
960
|
-
parent = parentNode.parent;
|
|
961
|
-
}
|
|
962
|
-
return ancestors;
|
|
963
|
-
};
|
|
964
|
-
const edgesMap = /* @__PURE__ */ new Map();
|
|
965
1017
|
const edges = this.computeEdges();
|
|
966
|
-
|
|
967
|
-
|
|
968
|
-
const source = nodesMap.get(edge.source);
|
|
969
|
-
const target = nodesMap.get(edge.target);
|
|
970
|
-
core.invariant(source, `Source node ${edge.source} not found`);
|
|
971
|
-
core.invariant(target, `Target node ${edge.target} not found`);
|
|
972
|
-
const sourceAncestors = ancestorsOf(source);
|
|
973
|
-
const targetAncestors = ancestorsOf(target);
|
|
974
|
-
const edgeParent = remeda.last(
|
|
975
|
-
core.commonHead(
|
|
976
|
-
remeda.reverse(sourceAncestors),
|
|
977
|
-
remeda.reverse(targetAncestors)
|
|
978
|
-
)
|
|
979
|
-
);
|
|
980
|
-
edge.parent = edgeParent?.id ?? null;
|
|
981
|
-
source.outEdges.push(edge.id);
|
|
982
|
-
target.inEdges.push(edge.id);
|
|
983
|
-
for (const sourceAncestor of sourceAncestors) {
|
|
984
|
-
if (sourceAncestor === edgeParent) {
|
|
985
|
-
break;
|
|
986
|
-
}
|
|
987
|
-
sourceAncestor.outEdges.push(edge.id);
|
|
988
|
-
}
|
|
989
|
-
for (const targetAncestor of targetAncestors) {
|
|
990
|
-
if (targetAncestor === edgeParent) {
|
|
991
|
-
break;
|
|
992
|
-
}
|
|
993
|
-
targetAncestor.inEdges.push(edge.id);
|
|
994
|
-
}
|
|
995
|
-
}
|
|
1018
|
+
const edgesMap = new Map(edges.map((edge) => [edge.id, edge]));
|
|
1019
|
+
this.linkNodesAndEdges(nodesMap, edges);
|
|
996
1020
|
let initialSort = elements.map((e) => core.nonNullable(nodesMap.get(e.id), `Node ${e.id} not found in nodesMap`));
|
|
997
1021
|
if (this.groups.length > 0) {
|
|
998
1022
|
initialSort = remeda.concat(
|
|
@@ -1033,9 +1057,6 @@ class ComputeCtx {
|
|
|
1033
1057
|
}
|
|
1034
1058
|
});
|
|
1035
1059
|
}
|
|
1036
|
-
get root() {
|
|
1037
|
-
return core.isScopedElementView(this.view) ? this.view.viewOf : null;
|
|
1038
|
-
}
|
|
1039
1060
|
computeEdges() {
|
|
1040
1061
|
return this.ctxEdges.map((e) => {
|
|
1041
1062
|
core.invariant(remeda.hasAtLeast(e.relations, 1), "Edge must have at least one relation");
|
|
@@ -1128,21 +1149,36 @@ class ComputeCtx {
|
|
|
1128
1149
|
);
|
|
1129
1150
|
});
|
|
1130
1151
|
}
|
|
1131
|
-
|
|
1132
|
-
|
|
1133
|
-
|
|
1134
|
-
|
|
1135
|
-
|
|
1136
|
-
|
|
1137
|
-
|
|
1138
|
-
|
|
1139
|
-
|
|
1140
|
-
|
|
1141
|
-
|
|
1142
|
-
|
|
1143
|
-
|
|
1144
|
-
|
|
1145
|
-
|
|
1152
|
+
linkNodesAndEdges(nodesMap, edges) {
|
|
1153
|
+
for (const edge of edges) {
|
|
1154
|
+
const source = nodesMap.get(edge.source);
|
|
1155
|
+
const target = nodesMap.get(edge.target);
|
|
1156
|
+
core.invariant(source, `Source node ${edge.source} not found`);
|
|
1157
|
+
core.invariant(target, `Target node ${edge.target} not found`);
|
|
1158
|
+
const sourceAncestors = this.ancestorsOf(source, nodesMap);
|
|
1159
|
+
const targetAncestors = this.ancestorsOf(target, nodesMap);
|
|
1160
|
+
const edgeParent = remeda.last(
|
|
1161
|
+
core.commonHead(
|
|
1162
|
+
remeda.reverse(sourceAncestors),
|
|
1163
|
+
remeda.reverse(targetAncestors)
|
|
1164
|
+
)
|
|
1165
|
+
);
|
|
1166
|
+
edge.parent = edgeParent?.id ?? null;
|
|
1167
|
+
source.outEdges.push(edge.id);
|
|
1168
|
+
target.inEdges.push(edge.id);
|
|
1169
|
+
for (const sourceAncestor of sourceAncestors) {
|
|
1170
|
+
if (sourceAncestor === edgeParent) {
|
|
1171
|
+
break;
|
|
1172
|
+
}
|
|
1173
|
+
sourceAncestor.outEdges.push(edge.id);
|
|
1174
|
+
}
|
|
1175
|
+
for (const targetAncestor of targetAncestors) {
|
|
1176
|
+
if (targetAncestor === edgeParent) {
|
|
1177
|
+
break;
|
|
1178
|
+
}
|
|
1179
|
+
targetAncestor.inEdges.push(edge.id);
|
|
1180
|
+
}
|
|
1181
|
+
}
|
|
1146
1182
|
}
|
|
1147
1183
|
addEdges(edges) {
|
|
1148
1184
|
const added = [];
|
|
@@ -1231,9 +1267,6 @@ class ComputeCtx {
|
|
|
1231
1267
|
}),
|
|
1232
1268
|
remeda.filter(remeda.isNonNull)
|
|
1233
1269
|
);
|
|
1234
|
-
if (excludedImplicits.size === 0) {
|
|
1235
|
-
return;
|
|
1236
|
-
}
|
|
1237
1270
|
this.ctxEdges = ctxEdges;
|
|
1238
1271
|
const remaining = this.includedElements;
|
|
1239
1272
|
if (remaining.size === 0) {
|
|
@@ -1410,6 +1443,19 @@ class ComputeCtx {
|
|
|
1410
1443
|
}
|
|
1411
1444
|
core.nonexhaustive(expr);
|
|
1412
1445
|
}
|
|
1446
|
+
ancestorsOf(node, nodesMap) {
|
|
1447
|
+
const ancestors = [];
|
|
1448
|
+
let parent = node.parent;
|
|
1449
|
+
while (parent) {
|
|
1450
|
+
const parentNode = nodesMap.get(parent);
|
|
1451
|
+
if (!parentNode) {
|
|
1452
|
+
break;
|
|
1453
|
+
}
|
|
1454
|
+
ancestors.push(parentNode);
|
|
1455
|
+
parent = parentNode.parent;
|
|
1456
|
+
}
|
|
1457
|
+
return ancestors;
|
|
1458
|
+
}
|
|
1413
1459
|
getEdgeLabel(relation) {
|
|
1414
1460
|
const labelParts = [];
|
|
1415
1461
|
if (remeda.isTruthy(relation.title)) {
|
|
@@ -1487,7 +1533,8 @@ class DynamicViewComputeCtx {
|
|
|
1487
1533
|
const {
|
|
1488
1534
|
docUri: _docUri,
|
|
1489
1535
|
// exclude docUri
|
|
1490
|
-
rules,
|
|
1536
|
+
rules: _rules,
|
|
1537
|
+
// exclude rules
|
|
1491
1538
|
steps: viewSteps,
|
|
1492
1539
|
...view
|
|
1493
1540
|
} = this.view;
|
|
@@ -1507,6 +1554,7 @@ class DynamicViewComputeCtx {
|
|
|
1507
1554
|
}
|
|
1508
1555
|
stepNum++;
|
|
1509
1556
|
}
|
|
1557
|
+
const rules = resolveGlobalRulesInDynamicView(this.view, this.graph.globals);
|
|
1510
1558
|
for (const rule of rules) {
|
|
1511
1559
|
if (core.isDynamicViewIncludeRule(rule)) {
|
|
1512
1560
|
for (const expr of rule.include) {
|
|
@@ -1660,7 +1708,13 @@ class LikeC4ModelGraph {
|
|
|
1660
1708
|
// Relationships inside the element, among descendants
|
|
1661
1709
|
#internal = new MapRelations();
|
|
1662
1710
|
#cacheAscendingSiblings = /* @__PURE__ */ new Map();
|
|
1663
|
-
|
|
1711
|
+
globals;
|
|
1712
|
+
constructor({ elements, relations, globals }) {
|
|
1713
|
+
this.globals = globals ?? {
|
|
1714
|
+
predicates: {},
|
|
1715
|
+
dynamicPredicates: {},
|
|
1716
|
+
styles: {}
|
|
1717
|
+
};
|
|
1664
1718
|
for (const el of Object.values(elements)) {
|
|
1665
1719
|
this.addElement(el);
|
|
1666
1720
|
}
|
|
@@ -1,8 +1,54 @@
|
|
|
1
|
-
import { Expr, whereOperatorAsPredicate, parentFqn, nonexhaustive, ComputedNode, isViewRuleGroup, isViewRulePredicate, isViewRuleStyle, nonNullable, ElementKind, compareByFqnHierarchically, DefaultThemeColor, DefaultElementShape, compareRelations, invariant, compareNatural, hasAtLeast, isAncestor,
|
|
2
|
-
import { pipe, map, pick, mapToObj, isTruthy,
|
|
1
|
+
import { isViewRuleGlobalPredicateRef, isViewRuleGlobalStyle, Expr, whereOperatorAsPredicate, parentFqn, nonexhaustive, ComputedNode, isViewRuleGroup, isViewRulePredicate, isViewRuleStyle, nonNullable, ElementKind, compareByFqnHierarchically, DefaultThemeColor, DefaultElementShape, compareRelations, invariant, compareNatural, hasAtLeast, isAncestor, isScopedElementView, isViewRuleAutoLayout, commonAncestor, commonHead, StepEdgeId, isDynamicViewParallelSteps, isDynamicViewIncludeRule, DefaultRelationshipColor, DefaultLineStyle, DefaultArrowType, ancestorsFqn, isSameHierarchy } from '@likec4/core';
|
|
2
|
+
import { isNullish, pipe, map, pick, mapToObj, isTruthy, omitBy, isEmpty, filter, isNot, anyPass, forEach, isDefined, groupBy, prop, mapValues, piped, unique, entries, flatMap, sortBy, sort, tap, difference, allPass, concat, omit, hasAtLeast as hasAtLeast$1, only, reduce, last, reverse, isNonNull, first, isString, isArray } from 'remeda';
|
|
3
3
|
import dagre from '@dagrejs/dagre';
|
|
4
|
+
import { logger } from '@likec4/log';
|
|
4
5
|
import objectHash from 'object-hash';
|
|
5
6
|
|
|
7
|
+
function resolveGlobalRulesInElementView(view, globals) {
|
|
8
|
+
return view.rules.reduce((acc, rule) => {
|
|
9
|
+
if (isViewRuleGlobalPredicateRef(rule)) {
|
|
10
|
+
const globalPredicates = globals.predicates[rule.predicateId];
|
|
11
|
+
if (isNullish(globalPredicates)) {
|
|
12
|
+
logger.warn(`Global predicate not found: ${rule.predicateId}`);
|
|
13
|
+
return acc;
|
|
14
|
+
}
|
|
15
|
+
return acc.concat(globalPredicates);
|
|
16
|
+
}
|
|
17
|
+
if (isViewRuleGlobalStyle(rule)) {
|
|
18
|
+
const globalStyles = globals.styles[rule.styleId];
|
|
19
|
+
if (isNullish(globalStyles)) {
|
|
20
|
+
logger.warn(`Global style not found: ${rule.styleId}`);
|
|
21
|
+
return acc;
|
|
22
|
+
}
|
|
23
|
+
return acc.concat(globalStyles);
|
|
24
|
+
}
|
|
25
|
+
acc.push(rule);
|
|
26
|
+
return acc;
|
|
27
|
+
}, []);
|
|
28
|
+
}
|
|
29
|
+
function resolveGlobalRulesInDynamicView(view, globals) {
|
|
30
|
+
return view.rules.reduce((acc, rule) => {
|
|
31
|
+
if (isViewRuleGlobalPredicateRef(rule)) {
|
|
32
|
+
const globalPredicates = globals.dynamicPredicates[rule.predicateId];
|
|
33
|
+
if (isNullish(globalPredicates)) {
|
|
34
|
+
logger.warn(`Global predicate not found: ${rule.predicateId}`);
|
|
35
|
+
return acc;
|
|
36
|
+
}
|
|
37
|
+
return acc.concat(globalPredicates);
|
|
38
|
+
}
|
|
39
|
+
if (isViewRuleGlobalStyle(rule)) {
|
|
40
|
+
const globalStyles = globals.styles[rule.styleId];
|
|
41
|
+
if (isNullish(globalStyles)) {
|
|
42
|
+
logger.warn(`Global style not found: ${rule.styleId}`);
|
|
43
|
+
return acc;
|
|
44
|
+
}
|
|
45
|
+
return acc.concat(globalStyles);
|
|
46
|
+
}
|
|
47
|
+
acc.push(rule);
|
|
48
|
+
return acc;
|
|
49
|
+
}, []);
|
|
50
|
+
}
|
|
51
|
+
|
|
6
52
|
function calcViewLayoutHash(view) {
|
|
7
53
|
const tohash = {
|
|
8
54
|
id: view.id,
|
|
@@ -114,7 +160,9 @@ function applyCustomElementProperties(_rules, _nodes) {
|
|
|
114
160
|
function relationExpressionToPredicates(expr) {
|
|
115
161
|
switch (true) {
|
|
116
162
|
case Expr.isRelationWhere(expr):
|
|
117
|
-
|
|
163
|
+
const predicate = relationExpressionToPredicates(expr.where.expr);
|
|
164
|
+
const where = whereOperatorAsPredicate(expr.where.condition);
|
|
165
|
+
return (e) => predicate(e) && where(e);
|
|
118
166
|
case Expr.isRelation(expr): {
|
|
119
167
|
const isSource = elementExprToPredicate(expr.source);
|
|
120
168
|
const isTarget = elementExprToPredicate(expr.target);
|
|
@@ -138,6 +186,7 @@ function relationExpressionToPredicates(expr) {
|
|
|
138
186
|
nonexhaustive(expr);
|
|
139
187
|
}
|
|
140
188
|
}
|
|
189
|
+
|
|
141
190
|
function applyCustomRelationProperties(_rules, nodes, _edges) {
|
|
142
191
|
const rules = _rules.flatMap(flattenGroupRules(Expr.isCustomRelationExpr));
|
|
143
192
|
const edges = Array.from(_edges);
|
|
@@ -155,12 +204,12 @@ function applyCustomRelationProperties(_rules, nodes, _edges) {
|
|
|
155
204
|
if (!source || !target) {
|
|
156
205
|
return;
|
|
157
206
|
}
|
|
158
|
-
if (satisfies({ source, target })) {
|
|
207
|
+
if (satisfies({ source, target, ...pick(edge, ["kind", "tags"]) })) {
|
|
159
208
|
edges[i] = {
|
|
160
209
|
...edge,
|
|
210
|
+
...props,
|
|
161
211
|
label: title ?? edge.label,
|
|
162
|
-
isCustomized: true
|
|
163
|
-
...props
|
|
212
|
+
isCustomized: true
|
|
164
213
|
};
|
|
165
214
|
}
|
|
166
215
|
});
|
|
@@ -176,10 +225,6 @@ function applyViewRuleStyles(_rules, nodes) {
|
|
|
176
225
|
for (const rule of rules) {
|
|
177
226
|
const predicates = [];
|
|
178
227
|
for (const target of rule.targets) {
|
|
179
|
-
if (Expr.isWildcard(target)) {
|
|
180
|
-
predicates.push(() => true);
|
|
181
|
-
break;
|
|
182
|
-
}
|
|
183
228
|
predicates.push(elementExprToPredicate(target));
|
|
184
229
|
}
|
|
185
230
|
pipe(
|
|
@@ -919,6 +964,25 @@ class ComputeCtx {
|
|
|
919
964
|
get activeGroup() {
|
|
920
965
|
return this.activeGroupStack[0] ?? this.__rootGroup;
|
|
921
966
|
}
|
|
967
|
+
get includedElements() {
|
|
968
|
+
return /* @__PURE__ */ new Set([
|
|
969
|
+
...this.explicits,
|
|
970
|
+
...this.ctxEdges.flatMap((e) => [e.source, e.target])
|
|
971
|
+
]);
|
|
972
|
+
}
|
|
973
|
+
get resolvedElements() {
|
|
974
|
+
return /* @__PURE__ */ new Set([
|
|
975
|
+
...this.explicits,
|
|
976
|
+
...this.implicits,
|
|
977
|
+
...this.ctxEdges.flatMap((e) => [e.source, e.target])
|
|
978
|
+
]);
|
|
979
|
+
}
|
|
980
|
+
get edges() {
|
|
981
|
+
return this.ctxEdges;
|
|
982
|
+
}
|
|
983
|
+
get root() {
|
|
984
|
+
return isScopedElementView(this.view) ? this.view.viewOf : null;
|
|
985
|
+
}
|
|
922
986
|
static elementView(view, graph) {
|
|
923
987
|
return new ComputeCtx(view, graph).compute();
|
|
924
988
|
}
|
|
@@ -927,9 +991,11 @@ class ComputeCtx {
|
|
|
927
991
|
const {
|
|
928
992
|
docUri: _docUri,
|
|
929
993
|
// exclude docUri
|
|
930
|
-
rules,
|
|
994
|
+
rules: _rules,
|
|
995
|
+
// exclude rules
|
|
931
996
|
...view
|
|
932
997
|
} = this.view;
|
|
998
|
+
const rules = resolveGlobalRulesInElementView(this.view, this.graph.globals);
|
|
933
999
|
const viewPredicates = rules.filter(anyPass([isViewRulePredicate, isViewRuleGroup]));
|
|
934
1000
|
if (this.root && viewPredicates.length == 0) {
|
|
935
1001
|
this.addElement(this.graph.element(this.root));
|
|
@@ -941,51 +1007,9 @@ class ComputeCtx {
|
|
|
941
1007
|
}
|
|
942
1008
|
const elements = [...this.includedElements];
|
|
943
1009
|
const nodesMap = buildComputeNodes(elements, this.groups);
|
|
944
|
-
const ancestorsOf = (node) => {
|
|
945
|
-
const ancestors = [];
|
|
946
|
-
let parent = node.parent;
|
|
947
|
-
while (parent) {
|
|
948
|
-
const parentNode = nodesMap.get(parent);
|
|
949
|
-
if (!parentNode) {
|
|
950
|
-
break;
|
|
951
|
-
}
|
|
952
|
-
ancestors.push(parentNode);
|
|
953
|
-
parent = parentNode.parent;
|
|
954
|
-
}
|
|
955
|
-
return ancestors;
|
|
956
|
-
};
|
|
957
|
-
const edgesMap = /* @__PURE__ */ new Map();
|
|
958
1010
|
const edges = this.computeEdges();
|
|
959
|
-
|
|
960
|
-
|
|
961
|
-
const source = nodesMap.get(edge.source);
|
|
962
|
-
const target = nodesMap.get(edge.target);
|
|
963
|
-
invariant(source, `Source node ${edge.source} not found`);
|
|
964
|
-
invariant(target, `Target node ${edge.target} not found`);
|
|
965
|
-
const sourceAncestors = ancestorsOf(source);
|
|
966
|
-
const targetAncestors = ancestorsOf(target);
|
|
967
|
-
const edgeParent = last(
|
|
968
|
-
commonHead(
|
|
969
|
-
reverse(sourceAncestors),
|
|
970
|
-
reverse(targetAncestors)
|
|
971
|
-
)
|
|
972
|
-
);
|
|
973
|
-
edge.parent = edgeParent?.id ?? null;
|
|
974
|
-
source.outEdges.push(edge.id);
|
|
975
|
-
target.inEdges.push(edge.id);
|
|
976
|
-
for (const sourceAncestor of sourceAncestors) {
|
|
977
|
-
if (sourceAncestor === edgeParent) {
|
|
978
|
-
break;
|
|
979
|
-
}
|
|
980
|
-
sourceAncestor.outEdges.push(edge.id);
|
|
981
|
-
}
|
|
982
|
-
for (const targetAncestor of targetAncestors) {
|
|
983
|
-
if (targetAncestor === edgeParent) {
|
|
984
|
-
break;
|
|
985
|
-
}
|
|
986
|
-
targetAncestor.inEdges.push(edge.id);
|
|
987
|
-
}
|
|
988
|
-
}
|
|
1011
|
+
const edgesMap = new Map(edges.map((edge) => [edge.id, edge]));
|
|
1012
|
+
this.linkNodesAndEdges(nodesMap, edges);
|
|
989
1013
|
let initialSort = elements.map((e) => nonNullable(nodesMap.get(e.id), `Node ${e.id} not found in nodesMap`));
|
|
990
1014
|
if (this.groups.length > 0) {
|
|
991
1015
|
initialSort = concat(
|
|
@@ -1026,9 +1050,6 @@ class ComputeCtx {
|
|
|
1026
1050
|
}
|
|
1027
1051
|
});
|
|
1028
1052
|
}
|
|
1029
|
-
get root() {
|
|
1030
|
-
return isScopedElementView(this.view) ? this.view.viewOf : null;
|
|
1031
|
-
}
|
|
1032
1053
|
computeEdges() {
|
|
1033
1054
|
return this.ctxEdges.map((e) => {
|
|
1034
1055
|
invariant(hasAtLeast$1(e.relations, 1), "Edge must have at least one relation");
|
|
@@ -1121,21 +1142,36 @@ class ComputeCtx {
|
|
|
1121
1142
|
);
|
|
1122
1143
|
});
|
|
1123
1144
|
}
|
|
1124
|
-
|
|
1125
|
-
|
|
1126
|
-
|
|
1127
|
-
|
|
1128
|
-
|
|
1129
|
-
|
|
1130
|
-
|
|
1131
|
-
|
|
1132
|
-
|
|
1133
|
-
|
|
1134
|
-
|
|
1135
|
-
|
|
1136
|
-
|
|
1137
|
-
|
|
1138
|
-
|
|
1145
|
+
linkNodesAndEdges(nodesMap, edges) {
|
|
1146
|
+
for (const edge of edges) {
|
|
1147
|
+
const source = nodesMap.get(edge.source);
|
|
1148
|
+
const target = nodesMap.get(edge.target);
|
|
1149
|
+
invariant(source, `Source node ${edge.source} not found`);
|
|
1150
|
+
invariant(target, `Target node ${edge.target} not found`);
|
|
1151
|
+
const sourceAncestors = this.ancestorsOf(source, nodesMap);
|
|
1152
|
+
const targetAncestors = this.ancestorsOf(target, nodesMap);
|
|
1153
|
+
const edgeParent = last(
|
|
1154
|
+
commonHead(
|
|
1155
|
+
reverse(sourceAncestors),
|
|
1156
|
+
reverse(targetAncestors)
|
|
1157
|
+
)
|
|
1158
|
+
);
|
|
1159
|
+
edge.parent = edgeParent?.id ?? null;
|
|
1160
|
+
source.outEdges.push(edge.id);
|
|
1161
|
+
target.inEdges.push(edge.id);
|
|
1162
|
+
for (const sourceAncestor of sourceAncestors) {
|
|
1163
|
+
if (sourceAncestor === edgeParent) {
|
|
1164
|
+
break;
|
|
1165
|
+
}
|
|
1166
|
+
sourceAncestor.outEdges.push(edge.id);
|
|
1167
|
+
}
|
|
1168
|
+
for (const targetAncestor of targetAncestors) {
|
|
1169
|
+
if (targetAncestor === edgeParent) {
|
|
1170
|
+
break;
|
|
1171
|
+
}
|
|
1172
|
+
targetAncestor.inEdges.push(edge.id);
|
|
1173
|
+
}
|
|
1174
|
+
}
|
|
1139
1175
|
}
|
|
1140
1176
|
addEdges(edges) {
|
|
1141
1177
|
const added = [];
|
|
@@ -1224,9 +1260,6 @@ class ComputeCtx {
|
|
|
1224
1260
|
}),
|
|
1225
1261
|
filter(isNonNull)
|
|
1226
1262
|
);
|
|
1227
|
-
if (excludedImplicits.size === 0) {
|
|
1228
|
-
return;
|
|
1229
|
-
}
|
|
1230
1263
|
this.ctxEdges = ctxEdges;
|
|
1231
1264
|
const remaining = this.includedElements;
|
|
1232
1265
|
if (remaining.size === 0) {
|
|
@@ -1403,6 +1436,19 @@ class ComputeCtx {
|
|
|
1403
1436
|
}
|
|
1404
1437
|
nonexhaustive(expr);
|
|
1405
1438
|
}
|
|
1439
|
+
ancestorsOf(node, nodesMap) {
|
|
1440
|
+
const ancestors = [];
|
|
1441
|
+
let parent = node.parent;
|
|
1442
|
+
while (parent) {
|
|
1443
|
+
const parentNode = nodesMap.get(parent);
|
|
1444
|
+
if (!parentNode) {
|
|
1445
|
+
break;
|
|
1446
|
+
}
|
|
1447
|
+
ancestors.push(parentNode);
|
|
1448
|
+
parent = parentNode.parent;
|
|
1449
|
+
}
|
|
1450
|
+
return ancestors;
|
|
1451
|
+
}
|
|
1406
1452
|
getEdgeLabel(relation) {
|
|
1407
1453
|
const labelParts = [];
|
|
1408
1454
|
if (isTruthy(relation.title)) {
|
|
@@ -1480,7 +1526,8 @@ class DynamicViewComputeCtx {
|
|
|
1480
1526
|
const {
|
|
1481
1527
|
docUri: _docUri,
|
|
1482
1528
|
// exclude docUri
|
|
1483
|
-
rules,
|
|
1529
|
+
rules: _rules,
|
|
1530
|
+
// exclude rules
|
|
1484
1531
|
steps: viewSteps,
|
|
1485
1532
|
...view
|
|
1486
1533
|
} = this.view;
|
|
@@ -1500,6 +1547,7 @@ class DynamicViewComputeCtx {
|
|
|
1500
1547
|
}
|
|
1501
1548
|
stepNum++;
|
|
1502
1549
|
}
|
|
1550
|
+
const rules = resolveGlobalRulesInDynamicView(this.view, this.graph.globals);
|
|
1503
1551
|
for (const rule of rules) {
|
|
1504
1552
|
if (isDynamicViewIncludeRule(rule)) {
|
|
1505
1553
|
for (const expr of rule.include) {
|
|
@@ -1653,7 +1701,13 @@ class LikeC4ModelGraph {
|
|
|
1653
1701
|
// Relationships inside the element, among descendants
|
|
1654
1702
|
#internal = new MapRelations();
|
|
1655
1703
|
#cacheAscendingSiblings = /* @__PURE__ */ new Map();
|
|
1656
|
-
|
|
1704
|
+
globals;
|
|
1705
|
+
constructor({ elements, relations, globals }) {
|
|
1706
|
+
this.globals = globals ?? {
|
|
1707
|
+
predicates: {},
|
|
1708
|
+
dynamicPredicates: {},
|
|
1709
|
+
styles: {}
|
|
1710
|
+
};
|
|
1657
1711
|
for (const el of Object.values(elements)) {
|
|
1658
1712
|
this.addElement(el);
|
|
1659
1713
|
}
|