@likec4/language-server 1.15.1 → 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.B8s2wfT_.cjs → language-server.Bd3NZ8uH.cjs} +123 -72
- package/dist/shared/{language-server.BT4WTbFI.mjs → language-server.C5gxpVUH.mjs} +125 -74
- 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.BuChFlda.mjs → language-server.D_13fWJQ.mjs} +177 -84
- package/dist/shared/{language-server.j-ShR6as.d.ts → language-server.DwyQ1FtY.d.ts} +44 -10
- package/dist/shared/{language-server.DfjkvknB.cjs → language-server.Dym6GL4P.cjs} +175 -82
- package/package.json +7 -7
- package/src/ast.ts +11 -3
- package/src/generated/ast.ts +111 -10
- package/src/generated/grammar.ts +1 -1
- package/src/like-c4.langium +19 -0
- 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 +63 -19
- 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/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(
|
|
@@ -1036,9 +1057,6 @@ class ComputeCtx {
|
|
|
1036
1057
|
}
|
|
1037
1058
|
});
|
|
1038
1059
|
}
|
|
1039
|
-
get root() {
|
|
1040
|
-
return core.isScopedElementView(this.view) ? this.view.viewOf : null;
|
|
1041
|
-
}
|
|
1042
1060
|
computeEdges() {
|
|
1043
1061
|
return this.ctxEdges.map((e) => {
|
|
1044
1062
|
core.invariant(remeda.hasAtLeast(e.relations, 1), "Edge must have at least one relation");
|
|
@@ -1131,21 +1149,36 @@ class ComputeCtx {
|
|
|
1131
1149
|
);
|
|
1132
1150
|
});
|
|
1133
1151
|
}
|
|
1134
|
-
|
|
1135
|
-
|
|
1136
|
-
|
|
1137
|
-
|
|
1138
|
-
|
|
1139
|
-
|
|
1140
|
-
|
|
1141
|
-
|
|
1142
|
-
|
|
1143
|
-
|
|
1144
|
-
|
|
1145
|
-
|
|
1146
|
-
|
|
1147
|
-
|
|
1148
|
-
|
|
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
|
+
}
|
|
1149
1182
|
}
|
|
1150
1183
|
addEdges(edges) {
|
|
1151
1184
|
const added = [];
|
|
@@ -1234,9 +1267,6 @@ class ComputeCtx {
|
|
|
1234
1267
|
}),
|
|
1235
1268
|
remeda.filter(remeda.isNonNull)
|
|
1236
1269
|
);
|
|
1237
|
-
if (excludedImplicits.size === 0) {
|
|
1238
|
-
return;
|
|
1239
|
-
}
|
|
1240
1270
|
this.ctxEdges = ctxEdges;
|
|
1241
1271
|
const remaining = this.includedElements;
|
|
1242
1272
|
if (remaining.size === 0) {
|
|
@@ -1413,6 +1443,19 @@ class ComputeCtx {
|
|
|
1413
1443
|
}
|
|
1414
1444
|
core.nonexhaustive(expr);
|
|
1415
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
|
+
}
|
|
1416
1459
|
getEdgeLabel(relation) {
|
|
1417
1460
|
const labelParts = [];
|
|
1418
1461
|
if (remeda.isTruthy(relation.title)) {
|
|
@@ -1490,7 +1533,8 @@ class DynamicViewComputeCtx {
|
|
|
1490
1533
|
const {
|
|
1491
1534
|
docUri: _docUri,
|
|
1492
1535
|
// exclude docUri
|
|
1493
|
-
rules,
|
|
1536
|
+
rules: _rules,
|
|
1537
|
+
// exclude rules
|
|
1494
1538
|
steps: viewSteps,
|
|
1495
1539
|
...view
|
|
1496
1540
|
} = this.view;
|
|
@@ -1510,6 +1554,7 @@ class DynamicViewComputeCtx {
|
|
|
1510
1554
|
}
|
|
1511
1555
|
stepNum++;
|
|
1512
1556
|
}
|
|
1557
|
+
const rules = resolveGlobalRulesInDynamicView(this.view, this.graph.globals);
|
|
1513
1558
|
for (const rule of rules) {
|
|
1514
1559
|
if (core.isDynamicViewIncludeRule(rule)) {
|
|
1515
1560
|
for (const expr of rule.include) {
|
|
@@ -1663,7 +1708,13 @@ class LikeC4ModelGraph {
|
|
|
1663
1708
|
// Relationships inside the element, among descendants
|
|
1664
1709
|
#internal = new MapRelations();
|
|
1665
1710
|
#cacheAscendingSiblings = /* @__PURE__ */ new Map();
|
|
1666
|
-
|
|
1711
|
+
globals;
|
|
1712
|
+
constructor({ elements, relations, globals }) {
|
|
1713
|
+
this.globals = globals ?? {
|
|
1714
|
+
predicates: {},
|
|
1715
|
+
dynamicPredicates: {},
|
|
1716
|
+
styles: {}
|
|
1717
|
+
};
|
|
1667
1718
|
for (const el of Object.values(elements)) {
|
|
1668
1719
|
this.addElement(el);
|
|
1669
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,
|
|
@@ -179,10 +225,6 @@ function applyViewRuleStyles(_rules, nodes) {
|
|
|
179
225
|
for (const rule of rules) {
|
|
180
226
|
const predicates = [];
|
|
181
227
|
for (const target of rule.targets) {
|
|
182
|
-
if (Expr.isWildcard(target)) {
|
|
183
|
-
predicates.push(() => true);
|
|
184
|
-
break;
|
|
185
|
-
}
|
|
186
228
|
predicates.push(elementExprToPredicate(target));
|
|
187
229
|
}
|
|
188
230
|
pipe(
|
|
@@ -922,6 +964,25 @@ class ComputeCtx {
|
|
|
922
964
|
get activeGroup() {
|
|
923
965
|
return this.activeGroupStack[0] ?? this.__rootGroup;
|
|
924
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
|
+
}
|
|
925
986
|
static elementView(view, graph) {
|
|
926
987
|
return new ComputeCtx(view, graph).compute();
|
|
927
988
|
}
|
|
@@ -930,9 +991,11 @@ class ComputeCtx {
|
|
|
930
991
|
const {
|
|
931
992
|
docUri: _docUri,
|
|
932
993
|
// exclude docUri
|
|
933
|
-
rules,
|
|
994
|
+
rules: _rules,
|
|
995
|
+
// exclude rules
|
|
934
996
|
...view
|
|
935
997
|
} = this.view;
|
|
998
|
+
const rules = resolveGlobalRulesInElementView(this.view, this.graph.globals);
|
|
936
999
|
const viewPredicates = rules.filter(anyPass([isViewRulePredicate, isViewRuleGroup]));
|
|
937
1000
|
if (this.root && viewPredicates.length == 0) {
|
|
938
1001
|
this.addElement(this.graph.element(this.root));
|
|
@@ -944,51 +1007,9 @@ class ComputeCtx {
|
|
|
944
1007
|
}
|
|
945
1008
|
const elements = [...this.includedElements];
|
|
946
1009
|
const nodesMap = buildComputeNodes(elements, this.groups);
|
|
947
|
-
const ancestorsOf = (node) => {
|
|
948
|
-
const ancestors = [];
|
|
949
|
-
let parent = node.parent;
|
|
950
|
-
while (parent) {
|
|
951
|
-
const parentNode = nodesMap.get(parent);
|
|
952
|
-
if (!parentNode) {
|
|
953
|
-
break;
|
|
954
|
-
}
|
|
955
|
-
ancestors.push(parentNode);
|
|
956
|
-
parent = parentNode.parent;
|
|
957
|
-
}
|
|
958
|
-
return ancestors;
|
|
959
|
-
};
|
|
960
|
-
const edgesMap = /* @__PURE__ */ new Map();
|
|
961
1010
|
const edges = this.computeEdges();
|
|
962
|
-
|
|
963
|
-
|
|
964
|
-
const source = nodesMap.get(edge.source);
|
|
965
|
-
const target = nodesMap.get(edge.target);
|
|
966
|
-
invariant(source, `Source node ${edge.source} not found`);
|
|
967
|
-
invariant(target, `Target node ${edge.target} not found`);
|
|
968
|
-
const sourceAncestors = ancestorsOf(source);
|
|
969
|
-
const targetAncestors = ancestorsOf(target);
|
|
970
|
-
const edgeParent = last(
|
|
971
|
-
commonHead(
|
|
972
|
-
reverse(sourceAncestors),
|
|
973
|
-
reverse(targetAncestors)
|
|
974
|
-
)
|
|
975
|
-
);
|
|
976
|
-
edge.parent = edgeParent?.id ?? null;
|
|
977
|
-
source.outEdges.push(edge.id);
|
|
978
|
-
target.inEdges.push(edge.id);
|
|
979
|
-
for (const sourceAncestor of sourceAncestors) {
|
|
980
|
-
if (sourceAncestor === edgeParent) {
|
|
981
|
-
break;
|
|
982
|
-
}
|
|
983
|
-
sourceAncestor.outEdges.push(edge.id);
|
|
984
|
-
}
|
|
985
|
-
for (const targetAncestor of targetAncestors) {
|
|
986
|
-
if (targetAncestor === edgeParent) {
|
|
987
|
-
break;
|
|
988
|
-
}
|
|
989
|
-
targetAncestor.inEdges.push(edge.id);
|
|
990
|
-
}
|
|
991
|
-
}
|
|
1011
|
+
const edgesMap = new Map(edges.map((edge) => [edge.id, edge]));
|
|
1012
|
+
this.linkNodesAndEdges(nodesMap, edges);
|
|
992
1013
|
let initialSort = elements.map((e) => nonNullable(nodesMap.get(e.id), `Node ${e.id} not found in nodesMap`));
|
|
993
1014
|
if (this.groups.length > 0) {
|
|
994
1015
|
initialSort = concat(
|
|
@@ -1029,9 +1050,6 @@ class ComputeCtx {
|
|
|
1029
1050
|
}
|
|
1030
1051
|
});
|
|
1031
1052
|
}
|
|
1032
|
-
get root() {
|
|
1033
|
-
return isScopedElementView(this.view) ? this.view.viewOf : null;
|
|
1034
|
-
}
|
|
1035
1053
|
computeEdges() {
|
|
1036
1054
|
return this.ctxEdges.map((e) => {
|
|
1037
1055
|
invariant(hasAtLeast$1(e.relations, 1), "Edge must have at least one relation");
|
|
@@ -1124,21 +1142,36 @@ class ComputeCtx {
|
|
|
1124
1142
|
);
|
|
1125
1143
|
});
|
|
1126
1144
|
}
|
|
1127
|
-
|
|
1128
|
-
|
|
1129
|
-
|
|
1130
|
-
|
|
1131
|
-
|
|
1132
|
-
|
|
1133
|
-
|
|
1134
|
-
|
|
1135
|
-
|
|
1136
|
-
|
|
1137
|
-
|
|
1138
|
-
|
|
1139
|
-
|
|
1140
|
-
|
|
1141
|
-
|
|
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
|
+
}
|
|
1142
1175
|
}
|
|
1143
1176
|
addEdges(edges) {
|
|
1144
1177
|
const added = [];
|
|
@@ -1227,9 +1260,6 @@ class ComputeCtx {
|
|
|
1227
1260
|
}),
|
|
1228
1261
|
filter(isNonNull)
|
|
1229
1262
|
);
|
|
1230
|
-
if (excludedImplicits.size === 0) {
|
|
1231
|
-
return;
|
|
1232
|
-
}
|
|
1233
1263
|
this.ctxEdges = ctxEdges;
|
|
1234
1264
|
const remaining = this.includedElements;
|
|
1235
1265
|
if (remaining.size === 0) {
|
|
@@ -1406,6 +1436,19 @@ class ComputeCtx {
|
|
|
1406
1436
|
}
|
|
1407
1437
|
nonexhaustive(expr);
|
|
1408
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
|
+
}
|
|
1409
1452
|
getEdgeLabel(relation) {
|
|
1410
1453
|
const labelParts = [];
|
|
1411
1454
|
if (isTruthy(relation.title)) {
|
|
@@ -1483,7 +1526,8 @@ class DynamicViewComputeCtx {
|
|
|
1483
1526
|
const {
|
|
1484
1527
|
docUri: _docUri,
|
|
1485
1528
|
// exclude docUri
|
|
1486
|
-
rules,
|
|
1529
|
+
rules: _rules,
|
|
1530
|
+
// exclude rules
|
|
1487
1531
|
steps: viewSteps,
|
|
1488
1532
|
...view
|
|
1489
1533
|
} = this.view;
|
|
@@ -1503,6 +1547,7 @@ class DynamicViewComputeCtx {
|
|
|
1503
1547
|
}
|
|
1504
1548
|
stepNum++;
|
|
1505
1549
|
}
|
|
1550
|
+
const rules = resolveGlobalRulesInDynamicView(this.view, this.graph.globals);
|
|
1506
1551
|
for (const rule of rules) {
|
|
1507
1552
|
if (isDynamicViewIncludeRule(rule)) {
|
|
1508
1553
|
for (const expr of rule.include) {
|
|
@@ -1656,7 +1701,13 @@ class LikeC4ModelGraph {
|
|
|
1656
1701
|
// Relationships inside the element, among descendants
|
|
1657
1702
|
#internal = new MapRelations();
|
|
1658
1703
|
#cacheAscendingSiblings = /* @__PURE__ */ new Map();
|
|
1659
|
-
|
|
1704
|
+
globals;
|
|
1705
|
+
constructor({ elements, relations, globals }) {
|
|
1706
|
+
this.globals = globals ?? {
|
|
1707
|
+
predicates: {},
|
|
1708
|
+
dynamicPredicates: {},
|
|
1709
|
+
styles: {}
|
|
1710
|
+
};
|
|
1660
1711
|
for (const el of Object.values(elements)) {
|
|
1661
1712
|
this.addElement(el);
|
|
1662
1713
|
}
|