@likec4/language-server 1.13.0 → 1.15.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/likec4lib.cjs +0 -1
- package/dist/likec4lib.mjs +0 -1
- package/dist/model-graph/index.cjs +1 -1
- package/dist/model-graph/index.mjs +1 -1
- package/dist/shared/{language-server.CbDa016p.cjs → language-server.80ITEDo5.cjs} +272 -64
- package/dist/shared/{language-server.C2ebP2pZ.cjs → language-server.BUtiWTKg.cjs} +383 -32
- package/dist/shared/{language-server.DFLaUdYu.mjs → language-server.DXC9g4_f.mjs} +274 -66
- package/dist/shared/{language-server.ryB8CivX.d.mts → language-server.DfMwkd2l.d.mts} +81 -15
- package/dist/shared/{language-server.Cnq_hgfm.d.cts → language-server.U2piOAVt.d.cts} +81 -15
- package/dist/shared/{language-server.eY70DuKx.d.ts → language-server.j-ShR6as.d.ts} +81 -15
- package/dist/shared/{language-server.CrE0nFSB.mjs → language-server.zY53FGJE.mjs} +385 -34
- package/package.json +12 -12
- package/src/ast.ts +11 -0
- package/src/generated/ast.ts +177 -17
- package/src/generated/grammar.ts +1 -1
- package/src/generated-lib/icons.ts +0 -1
- package/src/like-c4.langium +50 -4
- package/src/lsp/CompletionProvider.ts +70 -2
- package/src/model/model-builder.ts +25 -3
- package/src/model/model-parser.ts +150 -33
- package/src/model-graph/compute-view/__test__/fixture.ts +45 -4
- package/src/model-graph/compute-view/compute.ts +223 -40
- package/src/model-graph/compute-view/predicates.ts +12 -6
- package/src/model-graph/utils/applyCustomElementProperties.ts +18 -4
- package/src/model-graph/utils/applyCustomRelationProperties.ts +2 -1
- package/src/model-graph/utils/applyViewRuleStyles.ts +30 -25
- package/src/model-graph/utils/buildComputeNodes.ts +69 -17
- package/src/model-graph/utils/elementExpressionToPredicate.ts +3 -1
- package/src/model-graph/utils/sortNodes.ts +11 -7
- package/src/references/scope-computation.ts +24 -1
- package/src/validation/index.ts +4 -0
- package/src/validation/specification.ts +30 -0
- package/src/view-utils/index.ts +1 -0
- package/src/view-utils/resolve-global-rules.ts +72 -0
- package/dist/shared/language-server.B-9_mDoo.d.mts +0 -1238
- package/dist/shared/language-server.C3oS5yhF.d.cts +0 -1238
- package/dist/shared/language-server.r5AXAWzc.d.ts +0 -1238
|
@@ -61,8 +61,19 @@ function elementExprToPredicate(target) {
|
|
|
61
61
|
core.nonexhaustive(target);
|
|
62
62
|
}
|
|
63
63
|
|
|
64
|
+
function flattenGroupRules(guard) {
|
|
65
|
+
return (rule) => {
|
|
66
|
+
if (core.isViewRuleGroup(rule)) {
|
|
67
|
+
return rule.groupRules.flatMap(flattenGroupRules(guard));
|
|
68
|
+
}
|
|
69
|
+
if (core.isViewRulePredicate(rule)) {
|
|
70
|
+
return "include" in rule ? rule.include.filter(guard) : [];
|
|
71
|
+
}
|
|
72
|
+
return [];
|
|
73
|
+
};
|
|
74
|
+
}
|
|
64
75
|
function applyCustomElementProperties(_rules, _nodes) {
|
|
65
|
-
const rules = _rules.flatMap((
|
|
76
|
+
const rules = _rules.flatMap(flattenGroupRules(core.Expr.isCustomElement));
|
|
66
77
|
if (rules.length === 0) {
|
|
67
78
|
return _nodes;
|
|
68
79
|
}
|
|
@@ -74,7 +85,7 @@ function applyCustomElementProperties(_rules, _nodes) {
|
|
|
74
85
|
const notEmpty = !remeda.isEmpty(rest);
|
|
75
86
|
const satisfies = elementExprToPredicate(expr);
|
|
76
87
|
nodes.forEach((node, i) => {
|
|
77
|
-
if (!satisfies(node)) {
|
|
88
|
+
if (core.ComputedNode.isNodesGroup(node) || !satisfies(node)) {
|
|
78
89
|
return;
|
|
79
90
|
}
|
|
80
91
|
if (notEmpty) {
|
|
@@ -135,7 +146,7 @@ function relationExpressionToPredicates(expr) {
|
|
|
135
146
|
}
|
|
136
147
|
}
|
|
137
148
|
function applyCustomRelationProperties(_rules, nodes, _edges) {
|
|
138
|
-
const rules = _rules.flatMap((
|
|
149
|
+
const rules = _rules.flatMap(flattenGroupRules(core.Expr.isCustomRelationExpr));
|
|
139
150
|
const edges = Array.from(_edges);
|
|
140
151
|
if (rules.length === 0 || edges.length === 0) {
|
|
141
152
|
return edges;
|
|
@@ -178,29 +189,34 @@ function applyViewRuleStyles(_rules, nodes) {
|
|
|
178
189
|
}
|
|
179
190
|
predicates.push(elementExprToPredicate(target));
|
|
180
191
|
}
|
|
181
|
-
remeda.
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
...
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
192
|
+
remeda.pipe(
|
|
193
|
+
nodes,
|
|
194
|
+
remeda.filter(remeda.isNot(core.ComputedNode.isNodesGroup)),
|
|
195
|
+
remeda.filter(remeda.anyPass(predicates)),
|
|
196
|
+
remeda.forEach((n) => {
|
|
197
|
+
n.shape = rule.style.shape ?? n.shape;
|
|
198
|
+
n.color = rule.style.color ?? n.color;
|
|
199
|
+
if (remeda.isDefined(rule.style.icon)) {
|
|
200
|
+
n.icon = rule.style.icon;
|
|
201
|
+
}
|
|
202
|
+
if (remeda.isDefined(rule.notation)) {
|
|
203
|
+
n.notation = rule.notation;
|
|
204
|
+
}
|
|
205
|
+
let styleOverride;
|
|
206
|
+
if (remeda.isDefined(rule.style.border)) {
|
|
207
|
+
styleOverride = { border: rule.style.border };
|
|
208
|
+
}
|
|
209
|
+
if (remeda.isDefined(rule.style.opacity)) {
|
|
210
|
+
styleOverride = { ...styleOverride, opacity: rule.style.opacity };
|
|
211
|
+
}
|
|
212
|
+
if (styleOverride) {
|
|
213
|
+
n.style = {
|
|
214
|
+
...n.style,
|
|
215
|
+
...styleOverride
|
|
216
|
+
};
|
|
217
|
+
}
|
|
218
|
+
})
|
|
219
|
+
);
|
|
204
220
|
}
|
|
205
221
|
return nodes;
|
|
206
222
|
}
|
|
@@ -216,40 +232,80 @@ function updateDepthOfAncestors(node, nodes) {
|
|
|
216
232
|
node = parentNd;
|
|
217
233
|
}
|
|
218
234
|
}
|
|
219
|
-
function buildComputeNodes(elements) {
|
|
220
|
-
|
|
235
|
+
function buildComputeNodes(elements, groups) {
|
|
236
|
+
const nodesMap = /* @__PURE__ */ new Map();
|
|
237
|
+
const elementToGroup = /* @__PURE__ */ new Map();
|
|
238
|
+
groups?.forEach(({ id, parent, viewRule, explicits }) => {
|
|
239
|
+
if (parent) {
|
|
240
|
+
core.nonNullable(nodesMap.get(parent), `Parent group node ${parent} not found`).children.push(id);
|
|
241
|
+
}
|
|
242
|
+
nodesMap.set(id, {
|
|
243
|
+
id,
|
|
244
|
+
parent,
|
|
245
|
+
kind: core.ElementKind.Group,
|
|
246
|
+
title: viewRule.title ?? "",
|
|
247
|
+
color: viewRule.color ?? "muted",
|
|
248
|
+
shape: "rectangle",
|
|
249
|
+
children: [],
|
|
250
|
+
inEdges: [],
|
|
251
|
+
outEdges: [],
|
|
252
|
+
level: 0,
|
|
253
|
+
depth: 0,
|
|
254
|
+
description: null,
|
|
255
|
+
technology: null,
|
|
256
|
+
tags: null,
|
|
257
|
+
links: null,
|
|
258
|
+
style: {
|
|
259
|
+
border: viewRule.border ?? "dashed",
|
|
260
|
+
opacity: viewRule.opacity ?? 0
|
|
261
|
+
}
|
|
262
|
+
});
|
|
263
|
+
for (const e of explicits) {
|
|
264
|
+
elementToGroup.set(e.id, id);
|
|
265
|
+
}
|
|
266
|
+
});
|
|
267
|
+
return Array.from(elements).sort(core.compareByFqnHierarchically).reduce((map, { id, color, shape, style, kind, title, ...el }) => {
|
|
221
268
|
let parent = core.parentFqn(id);
|
|
222
269
|
let level = 0;
|
|
270
|
+
let parentNd;
|
|
223
271
|
while (parent) {
|
|
224
|
-
|
|
272
|
+
parentNd = map.get(parent);
|
|
225
273
|
if (parentNd) {
|
|
226
|
-
if (parentNd.children.length == 0) {
|
|
227
|
-
parentNd.depth = 1;
|
|
228
|
-
updateDepthOfAncestors(parentNd, map);
|
|
229
|
-
}
|
|
230
|
-
parentNd.children.push(id);
|
|
231
|
-
level = parentNd.level + 1;
|
|
232
274
|
break;
|
|
233
275
|
}
|
|
234
276
|
parent = core.parentFqn(parent);
|
|
235
277
|
}
|
|
278
|
+
if (!parentNd && elementToGroup.has(id)) {
|
|
279
|
+
parent = elementToGroup.get(id);
|
|
280
|
+
parentNd = map.get(parent);
|
|
281
|
+
}
|
|
282
|
+
if (parentNd) {
|
|
283
|
+
if (parentNd.children.length == 0) {
|
|
284
|
+
parentNd.depth = 1;
|
|
285
|
+
updateDepthOfAncestors(parentNd, map);
|
|
286
|
+
}
|
|
287
|
+
parentNd.children.push(id);
|
|
288
|
+
level = parentNd.level + 1;
|
|
289
|
+
}
|
|
236
290
|
const node = {
|
|
237
|
-
...el,
|
|
238
291
|
id,
|
|
239
292
|
parent,
|
|
240
|
-
|
|
293
|
+
kind,
|
|
294
|
+
title,
|
|
241
295
|
color: color ?? core.DefaultThemeColor,
|
|
242
296
|
shape: shape ?? core.DefaultElementShape,
|
|
243
297
|
children: [],
|
|
244
298
|
inEdges: [],
|
|
245
299
|
outEdges: [],
|
|
300
|
+
level,
|
|
301
|
+
...el,
|
|
246
302
|
style: {
|
|
247
303
|
...style
|
|
248
304
|
}
|
|
249
305
|
};
|
|
250
306
|
map.set(id, node);
|
|
251
307
|
return map;
|
|
252
|
-
},
|
|
308
|
+
}, nodesMap);
|
|
253
309
|
}
|
|
254
310
|
|
|
255
311
|
function buildElementNotations(nodes) {
|
|
@@ -321,9 +377,16 @@ function sortNodes({
|
|
|
321
377
|
nodes,
|
|
322
378
|
edges
|
|
323
379
|
}) {
|
|
324
|
-
if (
|
|
380
|
+
if (nodes.length < 2) {
|
|
325
381
|
return nodes;
|
|
326
382
|
}
|
|
383
|
+
if (edges.length === 0) {
|
|
384
|
+
return remeda.pipe(
|
|
385
|
+
nodes,
|
|
386
|
+
remeda.sort(core.compareByFqnHierarchically),
|
|
387
|
+
remeda.tap(sortChildren)
|
|
388
|
+
);
|
|
389
|
+
}
|
|
327
390
|
const g = new Graph({
|
|
328
391
|
compound: false,
|
|
329
392
|
directed: true,
|
|
@@ -358,15 +421,15 @@ function sortNodes({
|
|
|
358
421
|
if (sources.length === 0) {
|
|
359
422
|
sources = remeda.pipe(
|
|
360
423
|
nodes,
|
|
361
|
-
remeda.sort(core.compareByFqnHierarchically),
|
|
362
424
|
remeda.filter((n) => n.inEdges.length === 0 || n.parent === null),
|
|
425
|
+
remeda.sort(core.compareByFqnHierarchically),
|
|
363
426
|
remeda.map((n) => n.id)
|
|
364
427
|
);
|
|
365
428
|
}
|
|
366
429
|
const orderedIds = postorder(g, sources).reverse();
|
|
367
430
|
const sorted = orderedIds.map(getNode);
|
|
368
431
|
if (sorted.length < nodes.length) {
|
|
369
|
-
const unsorted = remeda.difference(nodes, sorted);
|
|
432
|
+
const unsorted = remeda.difference(nodes, sorted).sort(core.compareByFqnHierarchically);
|
|
370
433
|
sorted.push(...unsorted);
|
|
371
434
|
}
|
|
372
435
|
core.invariant(sorted.length === nodes.length, "Not all nodes were processed by graphlib");
|
|
@@ -453,7 +516,9 @@ function includeWildcardRef(_expr, where = NoFilter) {
|
|
|
453
516
|
])
|
|
454
517
|
];
|
|
455
518
|
for (const el of children) {
|
|
456
|
-
this.addEdges(this.graph.anyEdgesBetween(el, neighbours))
|
|
519
|
+
this.addEdges(this.graph.anyEdgesBetween(el, neighbours)).forEach((edge) => {
|
|
520
|
+
this.addImplicit(edge.source, edge.target);
|
|
521
|
+
});
|
|
457
522
|
}
|
|
458
523
|
if (!hasChildren && _elRoot) {
|
|
459
524
|
const edgesWithSiblings = this.graph.anyEdgesBetween(_elRoot, this.graph.siblings(root));
|
|
@@ -644,8 +709,9 @@ function includeIncomingExpr(expr, where) {
|
|
|
644
709
|
if (edges.length === 0) {
|
|
645
710
|
return;
|
|
646
711
|
}
|
|
647
|
-
this.addEdges(edges)
|
|
648
|
-
|
|
712
|
+
this.addEdges(edges).forEach((edge) => {
|
|
713
|
+
this.addImplicit(edge.target);
|
|
714
|
+
});
|
|
649
715
|
}
|
|
650
716
|
function excludeIncomingExpr(expr, where) {
|
|
651
717
|
let relations = filterRelations(edgesIncomingExpr.call(this, expr.incoming), where);
|
|
@@ -685,8 +751,9 @@ function includeOutgoingExpr(expr, where) {
|
|
|
685
751
|
if (edges.length === 0) {
|
|
686
752
|
return;
|
|
687
753
|
}
|
|
688
|
-
this.addEdges(edges)
|
|
689
|
-
|
|
754
|
+
this.addEdges(edges).forEach((edge) => {
|
|
755
|
+
this.addImplicit(edge.source);
|
|
756
|
+
});
|
|
690
757
|
}
|
|
691
758
|
function excludeOutgoingExpr(expr, where) {
|
|
692
759
|
const relations = filterRelations(edgesOutgoingExpr.call(this, expr.outgoing), where);
|
|
@@ -771,7 +838,9 @@ function includeRelationExpr(expr, where) {
|
|
|
771
838
|
if (expr.isBidirectional === true) {
|
|
772
839
|
edges.push(...this.graph.edgesBetween(targets, sources));
|
|
773
840
|
}
|
|
774
|
-
this.addEdges(filterEdges(edges, where))
|
|
841
|
+
this.addEdges(filterEdges(edges, where)).forEach((edge) => {
|
|
842
|
+
this.activeGroup.addImplicit(edge.source, edge.target);
|
|
843
|
+
});
|
|
775
844
|
}
|
|
776
845
|
function excludeRelationExpr(expr, where) {
|
|
777
846
|
const isSource = elementExprToPredicate(expr.source);
|
|
@@ -794,6 +863,50 @@ function compareEdges(a, b) {
|
|
|
794
863
|
{ source: b.source.id, target: b.target.id }
|
|
795
864
|
);
|
|
796
865
|
}
|
|
866
|
+
class NodesGroup {
|
|
867
|
+
constructor(id, viewRule, parent = null) {
|
|
868
|
+
this.id = id;
|
|
869
|
+
this.viewRule = viewRule;
|
|
870
|
+
this.parent = parent;
|
|
871
|
+
}
|
|
872
|
+
static kind = core.ElementKind.Group;
|
|
873
|
+
static root() {
|
|
874
|
+
return new NodesGroup("@root", { title: null, groupRules: [] });
|
|
875
|
+
}
|
|
876
|
+
static is(node) {
|
|
877
|
+
return node.kind === NodesGroup.kind;
|
|
878
|
+
}
|
|
879
|
+
explicits = /* @__PURE__ */ new Set();
|
|
880
|
+
implicits = /* @__PURE__ */ new Set();
|
|
881
|
+
/**
|
|
882
|
+
* Add element explicitly
|
|
883
|
+
* Included even without relationships
|
|
884
|
+
*/
|
|
885
|
+
addElement(...el) {
|
|
886
|
+
for (const r of el) {
|
|
887
|
+
this.explicits.add(r);
|
|
888
|
+
this.implicits.add(r);
|
|
889
|
+
}
|
|
890
|
+
}
|
|
891
|
+
/**
|
|
892
|
+
* Add element implicitly
|
|
893
|
+
* Included if only has relationships
|
|
894
|
+
*/
|
|
895
|
+
addImplicit(...el) {
|
|
896
|
+
for (const r of el) {
|
|
897
|
+
this.implicits.add(r);
|
|
898
|
+
}
|
|
899
|
+
}
|
|
900
|
+
excludeElement(...excludes) {
|
|
901
|
+
for (const el of excludes) {
|
|
902
|
+
this.explicits.delete(el);
|
|
903
|
+
this.implicits.delete(el);
|
|
904
|
+
}
|
|
905
|
+
}
|
|
906
|
+
isEmpty() {
|
|
907
|
+
return this.explicits.size === 0 && this.implicits.size === 0;
|
|
908
|
+
}
|
|
909
|
+
}
|
|
797
910
|
class ComputeCtx {
|
|
798
911
|
constructor(view, graph) {
|
|
799
912
|
this.view = view;
|
|
@@ -803,6 +916,16 @@ class ComputeCtx {
|
|
|
803
916
|
explicits = /* @__PURE__ */ new Set();
|
|
804
917
|
implicits = /* @__PURE__ */ new Set();
|
|
805
918
|
ctxEdges = [];
|
|
919
|
+
/**
|
|
920
|
+
* Root group - not included in the groups
|
|
921
|
+
* But used to accumulate elements that are not in any group
|
|
922
|
+
*/
|
|
923
|
+
__rootGroup = NodesGroup.root();
|
|
924
|
+
groups = [];
|
|
925
|
+
activeGroupStack = [];
|
|
926
|
+
get activeGroup() {
|
|
927
|
+
return this.activeGroupStack[0] ?? this.__rootGroup;
|
|
928
|
+
}
|
|
806
929
|
static elementView(view, graph) {
|
|
807
930
|
return new ComputeCtx(view, graph).compute();
|
|
808
931
|
}
|
|
@@ -814,14 +937,30 @@ class ComputeCtx {
|
|
|
814
937
|
rules,
|
|
815
938
|
...view
|
|
816
939
|
} = this.view;
|
|
817
|
-
const viewPredicates = rules.filter(core.isViewRulePredicate);
|
|
940
|
+
const viewPredicates = rules.filter(remeda.anyPass([core.isViewRulePredicate, core.isViewRuleGroup]));
|
|
818
941
|
if (this.root && viewPredicates.length == 0) {
|
|
819
942
|
this.addElement(this.graph.element(this.root));
|
|
820
943
|
}
|
|
821
944
|
this.processPredicates(viewPredicates);
|
|
822
945
|
this.removeRedundantImplicitEdges();
|
|
946
|
+
if (this.groups.length > 0) {
|
|
947
|
+
this.cleanGroupElements();
|
|
948
|
+
}
|
|
823
949
|
const elements = [...this.includedElements];
|
|
824
|
-
const nodesMap = buildComputeNodes(elements);
|
|
950
|
+
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
|
+
};
|
|
825
964
|
const edgesMap = /* @__PURE__ */ new Map();
|
|
826
965
|
const edges = this.computeEdges();
|
|
827
966
|
for (const edge of edges) {
|
|
@@ -830,25 +969,37 @@ class ComputeCtx {
|
|
|
830
969
|
const target = nodesMap.get(edge.target);
|
|
831
970
|
core.invariant(source, `Source node ${edge.source} not found`);
|
|
832
971
|
core.invariant(target, `Target node ${edge.target} not found`);
|
|
833
|
-
|
|
834
|
-
|
|
835
|
-
|
|
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;
|
|
836
981
|
source.outEdges.push(edge.id);
|
|
837
982
|
target.inEdges.push(edge.id);
|
|
838
|
-
for (const sourceAncestor of
|
|
839
|
-
if (sourceAncestor ===
|
|
983
|
+
for (const sourceAncestor of sourceAncestors) {
|
|
984
|
+
if (sourceAncestor === edgeParent) {
|
|
840
985
|
break;
|
|
841
986
|
}
|
|
842
|
-
|
|
987
|
+
sourceAncestor.outEdges.push(edge.id);
|
|
843
988
|
}
|
|
844
|
-
for (const targetAncestor of
|
|
845
|
-
if (targetAncestor ===
|
|
989
|
+
for (const targetAncestor of targetAncestors) {
|
|
990
|
+
if (targetAncestor === edgeParent) {
|
|
846
991
|
break;
|
|
847
992
|
}
|
|
848
|
-
|
|
993
|
+
targetAncestor.inEdges.push(edge.id);
|
|
849
994
|
}
|
|
850
995
|
}
|
|
851
|
-
|
|
996
|
+
let initialSort = elements.map((e) => core.nonNullable(nodesMap.get(e.id), `Node ${e.id} not found in nodesMap`));
|
|
997
|
+
if (this.groups.length > 0) {
|
|
998
|
+
initialSort = remeda.concat(
|
|
999
|
+
this.groups.map((g) => core.nonNullable(nodesMap.get(g.id), `Node ${g.id} not found in nodesMap`)),
|
|
1000
|
+
initialSort
|
|
1001
|
+
);
|
|
1002
|
+
}
|
|
852
1003
|
const nodes = applyCustomElementProperties(
|
|
853
1004
|
rules,
|
|
854
1005
|
applyViewRuleStyles(
|
|
@@ -994,6 +1145,7 @@ class ComputeCtx {
|
|
|
994
1145
|
return this.ctxEdges;
|
|
995
1146
|
}
|
|
996
1147
|
addEdges(edges) {
|
|
1148
|
+
const added = [];
|
|
997
1149
|
for (const e of edges) {
|
|
998
1150
|
if (!remeda.hasAtLeast(e.relations, 1)) {
|
|
999
1151
|
continue;
|
|
@@ -1003,10 +1155,13 @@ class ComputeCtx {
|
|
|
1003
1155
|
);
|
|
1004
1156
|
if (existing) {
|
|
1005
1157
|
existing.relations = remeda.unique([...existing.relations, ...e.relations]);
|
|
1158
|
+
added.push(existing);
|
|
1006
1159
|
continue;
|
|
1007
1160
|
}
|
|
1161
|
+
added.push(e);
|
|
1008
1162
|
this.ctxEdges.push(e);
|
|
1009
1163
|
}
|
|
1164
|
+
return added;
|
|
1010
1165
|
}
|
|
1011
1166
|
/**
|
|
1012
1167
|
* Add element explicitly
|
|
@@ -1014,6 +1169,14 @@ class ComputeCtx {
|
|
|
1014
1169
|
*/
|
|
1015
1170
|
addElement(...el) {
|
|
1016
1171
|
for (const r of el) {
|
|
1172
|
+
if (!this.explicits.has(r)) {
|
|
1173
|
+
this.activeGroup.addElement(r);
|
|
1174
|
+
} else if (this.activeGroup !== this.__rootGroup) {
|
|
1175
|
+
this.groups.forEach((g) => {
|
|
1176
|
+
g.implicits.delete(r);
|
|
1177
|
+
});
|
|
1178
|
+
this.activeGroup.addImplicit(r);
|
|
1179
|
+
}
|
|
1017
1180
|
this.explicits.add(r);
|
|
1018
1181
|
this.implicits.add(r);
|
|
1019
1182
|
}
|
|
@@ -1025,7 +1188,13 @@ class ComputeCtx {
|
|
|
1025
1188
|
addImplicit(...el) {
|
|
1026
1189
|
for (const r of el) {
|
|
1027
1190
|
this.implicits.add(r);
|
|
1191
|
+
if (this.activeGroup !== this.__rootGroup) {
|
|
1192
|
+
this.groups.forEach((g) => {
|
|
1193
|
+
g.implicits.delete(r);
|
|
1194
|
+
});
|
|
1195
|
+
}
|
|
1028
1196
|
}
|
|
1197
|
+
this.activeGroup.addImplicit(...el);
|
|
1029
1198
|
}
|
|
1030
1199
|
excludeElement(...excludes) {
|
|
1031
1200
|
for (const el of excludes) {
|
|
@@ -1033,12 +1202,11 @@ class ComputeCtx {
|
|
|
1033
1202
|
this.explicits.delete(el);
|
|
1034
1203
|
this.implicits.delete(el);
|
|
1035
1204
|
}
|
|
1205
|
+
this.__rootGroup.excludeElement(...excludes);
|
|
1206
|
+
this.groups.forEach((g) => {
|
|
1207
|
+
g.excludeElement(...excludes);
|
|
1208
|
+
});
|
|
1036
1209
|
}
|
|
1037
|
-
// protected excludeImplicit(...excludes: Element[]) {
|
|
1038
|
-
// for (const el of excludes) {
|
|
1039
|
-
// this.implicits.delete(el)
|
|
1040
|
-
// }
|
|
1041
|
-
// }
|
|
1042
1210
|
excludeRelation(...relations) {
|
|
1043
1211
|
if (relations.length === 0) {
|
|
1044
1212
|
return;
|
|
@@ -1070,11 +1238,15 @@ class ComputeCtx {
|
|
|
1070
1238
|
const remaining = this.includedElements;
|
|
1071
1239
|
if (remaining.size === 0) {
|
|
1072
1240
|
this.implicits.clear();
|
|
1241
|
+
this.__rootGroup.implicits.clear();
|
|
1242
|
+
this.groups.forEach((g) => g.implicits.clear());
|
|
1073
1243
|
return;
|
|
1074
1244
|
}
|
|
1075
1245
|
for (const el of excludedImplicits) {
|
|
1076
1246
|
if (!remaining.has(el)) {
|
|
1077
1247
|
this.implicits.delete(el);
|
|
1248
|
+
this.__rootGroup.implicits.delete(el);
|
|
1249
|
+
this.groups.forEach((g) => g.implicits.delete(el));
|
|
1078
1250
|
}
|
|
1079
1251
|
}
|
|
1080
1252
|
}
|
|
@@ -1082,6 +1254,9 @@ class ComputeCtx {
|
|
|
1082
1254
|
this.explicits.clear();
|
|
1083
1255
|
this.implicits.clear();
|
|
1084
1256
|
this.ctxEdges = [];
|
|
1257
|
+
this.__rootGroup = NodesGroup.root();
|
|
1258
|
+
this.groups = [];
|
|
1259
|
+
this.activeGroupStack = [];
|
|
1085
1260
|
}
|
|
1086
1261
|
// Filter out edges if there are edges between descendants
|
|
1087
1262
|
// i.e. remove implicit edges, derived from childs
|
|
@@ -1124,8 +1299,41 @@ class ComputeCtx {
|
|
|
1124
1299
|
return acc;
|
|
1125
1300
|
}, []);
|
|
1126
1301
|
}
|
|
1302
|
+
cleanGroupElements() {
|
|
1303
|
+
const unprocessed = new Set(remeda.difference(
|
|
1304
|
+
[...this.includedElements],
|
|
1305
|
+
[...this.__rootGroup.explicits]
|
|
1306
|
+
));
|
|
1307
|
+
for (const group of this.groups) {
|
|
1308
|
+
const explicits = [...group.explicits];
|
|
1309
|
+
group.explicits.clear();
|
|
1310
|
+
for (const el of explicits) {
|
|
1311
|
+
if (unprocessed.delete(el)) {
|
|
1312
|
+
group.explicits.add(el);
|
|
1313
|
+
}
|
|
1314
|
+
}
|
|
1315
|
+
}
|
|
1316
|
+
for (const group of this.groups) {
|
|
1317
|
+
for (const el of group.implicits) {
|
|
1318
|
+
if (unprocessed.delete(el)) {
|
|
1319
|
+
group.explicits.add(el);
|
|
1320
|
+
}
|
|
1321
|
+
}
|
|
1322
|
+
group.implicits.clear();
|
|
1323
|
+
}
|
|
1324
|
+
}
|
|
1127
1325
|
processPredicates(viewRules) {
|
|
1128
1326
|
for (const rule of viewRules) {
|
|
1327
|
+
if (core.isViewRuleGroup(rule)) {
|
|
1328
|
+
const parent = remeda.first(this.activeGroupStack);
|
|
1329
|
+
const groupId = `@gr${this.groups.length + 1}`;
|
|
1330
|
+
const group = new NodesGroup(groupId, rule, parent?.id ?? null);
|
|
1331
|
+
this.groups.push(group);
|
|
1332
|
+
this.activeGroupStack.unshift(group);
|
|
1333
|
+
this.processPredicates(rule.groupRules);
|
|
1334
|
+
this.activeGroupStack.shift();
|
|
1335
|
+
continue;
|
|
1336
|
+
}
|
|
1129
1337
|
const isInclude = "include" in rule;
|
|
1130
1338
|
const exprs = rule.include ?? rule.exclude;
|
|
1131
1339
|
for (const expr of exprs) {
|