@likec4/core 0.7.0 → 0.18.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/dist/colors.d.ts +79 -0
- package/dist/colors.js +94 -0
- package/dist/compute-view/EdgeBuilder.js +1 -1
- package/dist/compute-view/compute-ctx.d.ts +18 -0
- package/dist/compute-view/compute-ctx.js +25 -0
- package/dist/compute-view/compute-element-view.d.ts +4 -0
- package/dist/compute-view/compute-element-view.js +416 -0
- package/dist/compute-view/compute.d.ts +1 -2
- package/dist/compute-view/compute.js +1 -1
- package/dist/index.d.ts +1 -0
- package/dist/index.js +1 -0
- package/dist/model-index/ModelIndex.js +3 -3
- package/dist/types/diagram.d.ts +6 -0
- package/dist/types/element.d.ts +2 -2
- package/dist/utils/compute-node-levels.d.ts +8 -0
- package/dist/utils/compute-node-levels.js +31 -0
- package/dist/utils/fqn.d.ts +2 -0
- package/dist/utils/fqn.js +22 -1
- package/dist/utils/index.d.ts +1 -0
- package/dist/utils/index.js +1 -0
- package/dist/utils/relations.d.ts +2 -1
- package/dist/utils/relations.js +10 -4
- package/package.json +18 -10
- package/dist/__test__/data.d.ts +0 -174
- package/dist/__test__/data.js +0 -188
- package/dist/__test__/index.d.ts +0 -2
- package/dist/__test__/index.js +0 -1
- package/dist/compute-view/compute.element-view.d.ts +0 -5
- package/dist/compute-view/compute.element-view.js +0 -168
- package/dist/compute-view/utils/evaluate-expression.d.ts +0 -11
- package/dist/compute-view/utils/evaluate-expression.js +0 -186
|
@@ -1,168 +0,0 @@
|
|
|
1
|
-
import { anyPass, filter, head } from 'rambdax';
|
|
2
|
-
import { DefaultElementShape, DefaultThemeColor } from '../types';
|
|
3
|
-
import * as Expression from '../types/expression';
|
|
4
|
-
import { isViewRuleAutoLayout, isViewRuleExpression, isViewRuleStyle } from '../types/view';
|
|
5
|
-
import { Relations, compareByFqnHierarchically, failExpectedNever, isSameHierarchy, parentFqn } from '../utils';
|
|
6
|
-
import { EdgeBuilder } from './EdgeBuilder';
|
|
7
|
-
import { anyPossibleRelations } from './utils/anyPossibleRelations';
|
|
8
|
-
import { evaluateExpression } from './utils/evaluate-expression';
|
|
9
|
-
import { sortNodes } from './utils/sortNodes';
|
|
10
|
-
function updateSetWith(set, elements, addToSet = true) {
|
|
11
|
-
for (const e of elements) {
|
|
12
|
-
addToSet ? set.add(e) : set.delete(e);
|
|
13
|
-
}
|
|
14
|
-
}
|
|
15
|
-
function transformToNodes(elementsIterator, index, currentViewid) {
|
|
16
|
-
return Array.from(elementsIterator)
|
|
17
|
-
.sort(compareByFqnHierarchically)
|
|
18
|
-
.reduce((map, { id, title, color, shape, description }) => {
|
|
19
|
-
let parent = parentFqn(id);
|
|
20
|
-
while (parent) {
|
|
21
|
-
if (map.has(parent)) {
|
|
22
|
-
break;
|
|
23
|
-
}
|
|
24
|
-
parent = parentFqn(parent);
|
|
25
|
-
}
|
|
26
|
-
const navigateTo = head(index.defaultViewOf(id).filter(v => v !== currentViewid));
|
|
27
|
-
map.set(id, Object.assign({
|
|
28
|
-
id,
|
|
29
|
-
parent,
|
|
30
|
-
title,
|
|
31
|
-
color: color ?? DefaultThemeColor,
|
|
32
|
-
shape: shape ?? DefaultElementShape,
|
|
33
|
-
children: []
|
|
34
|
-
}, description ? { description } : {}, navigateTo ? { navigateTo } : {}));
|
|
35
|
-
if (parent) {
|
|
36
|
-
map.get(parent)?.children.push(id);
|
|
37
|
-
}
|
|
38
|
-
return map;
|
|
39
|
-
}, new Map());
|
|
40
|
-
}
|
|
41
|
-
function applyViewRuleStyles(rules, nodes) {
|
|
42
|
-
for (const rule of rules) {
|
|
43
|
-
const predicates = [];
|
|
44
|
-
if (!rule.style.color && !rule.style.shape) {
|
|
45
|
-
// skip empty
|
|
46
|
-
continue;
|
|
47
|
-
}
|
|
48
|
-
for (const target of rule.targets) {
|
|
49
|
-
if (Expression.isWildcard(target)) {
|
|
50
|
-
predicates.push(() => true);
|
|
51
|
-
break;
|
|
52
|
-
}
|
|
53
|
-
if (Expression.isElementRef(target)) {
|
|
54
|
-
const { element, isDescedants } = target;
|
|
55
|
-
predicates.push(isDescedants ? n => n.id.startsWith(element + '.') : n => n.id === element);
|
|
56
|
-
continue;
|
|
57
|
-
}
|
|
58
|
-
failExpectedNever(target);
|
|
59
|
-
}
|
|
60
|
-
filter(anyPass(predicates), nodes).forEach(n => {
|
|
61
|
-
n.shape = rule.style.shape ?? n.shape;
|
|
62
|
-
n.color = rule.style.color ?? n.color;
|
|
63
|
-
});
|
|
64
|
-
}
|
|
65
|
-
return nodes;
|
|
66
|
-
}
|
|
67
|
-
export function computeElementView(view, index) {
|
|
68
|
-
const relations = new Set();
|
|
69
|
-
const elements = new Set();
|
|
70
|
-
const neighbours = new Set();
|
|
71
|
-
const rootElement = view.viewOf ?? null;
|
|
72
|
-
const rulesInclude = view.rules.filter(isViewRuleExpression);
|
|
73
|
-
if (rootElement && rulesInclude.length == 0) {
|
|
74
|
-
elements.add(index.find(rootElement));
|
|
75
|
-
}
|
|
76
|
-
for (const { isInclude, exprs } of rulesInclude) {
|
|
77
|
-
for (const expr of exprs) {
|
|
78
|
-
let { elements: newElements, neighbours: newNeighbours, relations: newRelations } = evaluateExpression(index, expr, rootElement);
|
|
79
|
-
if (isInclude) {
|
|
80
|
-
const filters = [];
|
|
81
|
-
// When include element(s) without newNeighbours, include in-out relations
|
|
82
|
-
if (elements.size > 0 &&
|
|
83
|
-
newElements.length > 0 &&
|
|
84
|
-
newNeighbours.length === 0 &&
|
|
85
|
-
Expression.isElement(expr)) {
|
|
86
|
-
for (const e of elements) {
|
|
87
|
-
for (const newE of newElements) {
|
|
88
|
-
if (!isSameHierarchy(e, newE)) {
|
|
89
|
-
filters.push(Relations.isAnyBetween(e.id, newE.id));
|
|
90
|
-
}
|
|
91
|
-
}
|
|
92
|
-
}
|
|
93
|
-
}
|
|
94
|
-
// // When include elements by tag or kind, include in-out relations
|
|
95
|
-
// if (elements.size > 0 && newElements.length > 0 && (Expression.isElementKind(expr) || Expression.isElementTag(expr))) {
|
|
96
|
-
// for (const e of elements) {
|
|
97
|
-
// for (const newE of newElements) {
|
|
98
|
-
// if (e.id !== newE.id && !isAncestor(e, newE) && !isAncestor(newE, e)) {
|
|
99
|
-
// filters.push(isAnyRelationBetween(e.id, newE.id))
|
|
100
|
-
// }
|
|
101
|
-
// }
|
|
102
|
-
// }
|
|
103
|
-
// }
|
|
104
|
-
if (filters.length > 0) {
|
|
105
|
-
newRelations = newRelations.concat(index.filterRelations(anyPass(filters)));
|
|
106
|
-
}
|
|
107
|
-
}
|
|
108
|
-
else {
|
|
109
|
-
if (Expression.isAnyRelation(expr)) {
|
|
110
|
-
// Exclude only relations, but not elements and neighbours
|
|
111
|
-
newNeighbours = [];
|
|
112
|
-
newElements = [];
|
|
113
|
-
}
|
|
114
|
-
else {
|
|
115
|
-
newNeighbours = newNeighbours.concat(newElements);
|
|
116
|
-
// Also exclude nested elements from current neighbours
|
|
117
|
-
// for (const n of neighbours) {
|
|
118
|
-
// if (newNeighbours.some(e => n.id.startsWith(e.id + '.'))) {
|
|
119
|
-
// newNeighbours.push(n)
|
|
120
|
-
// }
|
|
121
|
-
// }
|
|
122
|
-
// Do not exclude relations
|
|
123
|
-
newRelations = [];
|
|
124
|
-
}
|
|
125
|
-
}
|
|
126
|
-
updateSetWith(elements, newElements, isInclude);
|
|
127
|
-
updateSetWith(relations, newRelations, isInclude);
|
|
128
|
-
updateSetWith(neighbours, newNeighbours, isInclude);
|
|
129
|
-
}
|
|
130
|
-
}
|
|
131
|
-
const elementsIds = new Set([...elements].map(e => e.id));
|
|
132
|
-
const edgeBuilder = new EdgeBuilder();
|
|
133
|
-
const resolvedRelations = [...relations];
|
|
134
|
-
for (const [source, target] of anyPossibleRelations([...elements, ...neighbours])) {
|
|
135
|
-
if (!elementsIds.has(source.id) && !elementsIds.has(target.id)) {
|
|
136
|
-
continue;
|
|
137
|
-
}
|
|
138
|
-
const findPredicate = Relations.isBetween(source.id, target.id);
|
|
139
|
-
let idx = resolvedRelations.findIndex(findPredicate);
|
|
140
|
-
while (idx >= 0) {
|
|
141
|
-
const [rel] = resolvedRelations.splice(idx, 1);
|
|
142
|
-
if (rel) {
|
|
143
|
-
elements.add(source);
|
|
144
|
-
elements.add(target);
|
|
145
|
-
edgeBuilder.add(source.id, target.id, rel);
|
|
146
|
-
}
|
|
147
|
-
idx = resolvedRelations.findIndex(findPredicate);
|
|
148
|
-
}
|
|
149
|
-
}
|
|
150
|
-
const nodesreg = transformToNodes(elements, index, view.id);
|
|
151
|
-
const edges = edgeBuilder.build().map(edge => {
|
|
152
|
-
while (edge.parent) {
|
|
153
|
-
if (nodesreg.has(edge.parent)) {
|
|
154
|
-
break;
|
|
155
|
-
}
|
|
156
|
-
edge.parent = parentFqn(edge.parent);
|
|
157
|
-
}
|
|
158
|
-
return edge;
|
|
159
|
-
});
|
|
160
|
-
const nodes = applyViewRuleStyles(view.rules.filter(isViewRuleStyle), sortNodes(nodesreg, edges));
|
|
161
|
-
const autoLayoutRule = view.rules.find(isViewRuleAutoLayout);
|
|
162
|
-
return {
|
|
163
|
-
...view,
|
|
164
|
-
autoLayout: autoLayoutRule?.autoLayout ?? 'TB',
|
|
165
|
-
nodes,
|
|
166
|
-
edges
|
|
167
|
-
};
|
|
168
|
-
}
|
|
@@ -1,11 +0,0 @@
|
|
|
1
|
-
import type { ModelIndex } from '../../model-index';
|
|
2
|
-
import type { Element, Fqn, Relation, Expression } from '../../types';
|
|
3
|
-
export declare const keepLeafs: (elements: Element[]) => Element[];
|
|
4
|
-
interface EvaluateViewExpressionResult {
|
|
5
|
-
elements: Element[];
|
|
6
|
-
neighbours: Element[];
|
|
7
|
-
relations: Relation[];
|
|
8
|
-
}
|
|
9
|
-
export declare function evaluateExpression(index: ModelIndex, expr: Expression, rootElement: Fqn | null): EvaluateViewExpressionResult;
|
|
10
|
-
export {};
|
|
11
|
-
//# sourceMappingURL=evaluate-expression.d.ts.map
|
|
@@ -1,186 +0,0 @@
|
|
|
1
|
-
import { anyPass, map, pluck, uniq } from 'rambdax';
|
|
2
|
-
import * as Expr from '../../types/expression';
|
|
3
|
-
import { failExpectedNever, isAncestor } from '../../utils';
|
|
4
|
-
import { isBetween, isIncoming, isInside, isOutgoing } from '../../utils/relations';
|
|
5
|
-
import { anyPossibleRelations } from './anyPossibleRelations';
|
|
6
|
-
const dropNested = (elements) => {
|
|
7
|
-
return elements.reduce((acc, current) => {
|
|
8
|
-
if (acc.length === 0)
|
|
9
|
-
return [current];
|
|
10
|
-
// current is a child of some in acc
|
|
11
|
-
if (acc.some(p => p.id === current.id || isAncestor(p, current))) {
|
|
12
|
-
return acc;
|
|
13
|
-
}
|
|
14
|
-
return [
|
|
15
|
-
// drop children of current
|
|
16
|
-
...acc.filter(e => !isAncestor(current, e)),
|
|
17
|
-
current
|
|
18
|
-
];
|
|
19
|
-
}, []);
|
|
20
|
-
};
|
|
21
|
-
export const keepLeafs = (elements) => {
|
|
22
|
-
return elements.reduce((acc, current) => {
|
|
23
|
-
if (acc.length === 0)
|
|
24
|
-
return [current];
|
|
25
|
-
// current is an ancestor of some in acc
|
|
26
|
-
if (acc.some(p => p.id === current.id || isAncestor(current, p))) {
|
|
27
|
-
return acc;
|
|
28
|
-
}
|
|
29
|
-
return [
|
|
30
|
-
// drop ancestors of current
|
|
31
|
-
...acc.filter(e => !isAncestor(e, current)),
|
|
32
|
-
current
|
|
33
|
-
];
|
|
34
|
-
}, []);
|
|
35
|
-
};
|
|
36
|
-
const evaluateElementExpression = (index, expr, rootElement = null) => {
|
|
37
|
-
let elements = [];
|
|
38
|
-
let neighbours = [];
|
|
39
|
-
let relations = [];
|
|
40
|
-
// const inOutRelations = (elements: Element[]) => {
|
|
41
|
-
// if (elements.length == 0) return []
|
|
42
|
-
// const filters = dropNested(elements).map(e => isAnyInOut(e.id))
|
|
43
|
-
// return index.filterRelations(anyPass(filters))
|
|
44
|
-
// }
|
|
45
|
-
const allRelationsBetween = (elements) => {
|
|
46
|
-
if (elements.length <= 1)
|
|
47
|
-
return [];
|
|
48
|
-
const filters = [];
|
|
49
|
-
for (const [source, target] of anyPossibleRelations(elements)) {
|
|
50
|
-
filters.push(isBetween(source.id, target.id));
|
|
51
|
-
}
|
|
52
|
-
return filters.length ? index.filterRelations(anyPass(filters)) : [];
|
|
53
|
-
};
|
|
54
|
-
// WildcardExpression
|
|
55
|
-
if (Expr.isWildcard(expr)) {
|
|
56
|
-
if (rootElement) {
|
|
57
|
-
elements = [index.find(rootElement), ...index.children(rootElement)];
|
|
58
|
-
neighbours = [
|
|
59
|
-
...index.siblings(rootElement),
|
|
60
|
-
...index.ancestors(rootElement).flatMap(a => [...index.siblings(a.id)])
|
|
61
|
-
];
|
|
62
|
-
relations = index.filterRelations(anyPass([isInside(rootElement), isIncoming(rootElement), isOutgoing(rootElement)]));
|
|
63
|
-
}
|
|
64
|
-
else {
|
|
65
|
-
elements = index.rootElements();
|
|
66
|
-
neighbours = elements;
|
|
67
|
-
relations = allRelationsBetween(elements);
|
|
68
|
-
}
|
|
69
|
-
return {
|
|
70
|
-
elements,
|
|
71
|
-
neighbours,
|
|
72
|
-
relations
|
|
73
|
-
};
|
|
74
|
-
}
|
|
75
|
-
// Identifier
|
|
76
|
-
if (Expr.isElementRef(expr)) {
|
|
77
|
-
elements = expr.isDescedants ? index.children(expr.element) : [index.find(expr.element)];
|
|
78
|
-
if (expr.isDescedants) {
|
|
79
|
-
relations = index.filterRelations(isInside(expr.element));
|
|
80
|
-
// relations = index.filterRelations(anyPass([
|
|
81
|
-
// isBetween(expr.element),
|
|
82
|
-
// isIncoming(expr.element),
|
|
83
|
-
// isOutgoing(expr.element),
|
|
84
|
-
// ]))
|
|
85
|
-
// } else {
|
|
86
|
-
// relations = index.filterRelations(anyPass([
|
|
87
|
-
// isIncoming(expr.element),
|
|
88
|
-
// isOutgoing(expr.element)
|
|
89
|
-
// ]))
|
|
90
|
-
}
|
|
91
|
-
return {
|
|
92
|
-
elements,
|
|
93
|
-
neighbours,
|
|
94
|
-
relations
|
|
95
|
-
};
|
|
96
|
-
}
|
|
97
|
-
failExpectedNever(expr);
|
|
98
|
-
};
|
|
99
|
-
export function evaluateExpression(index, expr, rootElement) {
|
|
100
|
-
const elements = [];
|
|
101
|
-
let neighbours = [];
|
|
102
|
-
let relations = [];
|
|
103
|
-
if (Expr.isInOut(expr)) {
|
|
104
|
-
const targets = evaluateElementExpression(index, expr.inout).elements;
|
|
105
|
-
for (const target of targets) {
|
|
106
|
-
const incoming = index.filterRelations(isIncoming(target.id));
|
|
107
|
-
const outgoing = index.filterRelations(isOutgoing(target.id));
|
|
108
|
-
if (incoming.length + outgoing.length > 0) {
|
|
109
|
-
elements.push(target);
|
|
110
|
-
neighbours = neighbours.concat(map(index.find, [...pluck('source', incoming), ...pluck('target', outgoing)]));
|
|
111
|
-
relations = relations.concat([...incoming, ...outgoing]);
|
|
112
|
-
}
|
|
113
|
-
}
|
|
114
|
-
return {
|
|
115
|
-
elements: uniq(elements),
|
|
116
|
-
neighbours: dropNested(neighbours),
|
|
117
|
-
relations: uniq(relations)
|
|
118
|
-
};
|
|
119
|
-
}
|
|
120
|
-
if (Expr.isIncoming(expr)) {
|
|
121
|
-
const targets = evaluateElementExpression(index, expr.incoming).elements;
|
|
122
|
-
for (const target of targets) {
|
|
123
|
-
const incoming = index.filterRelations(isIncoming(target.id));
|
|
124
|
-
if (incoming.length > 0) {
|
|
125
|
-
elements.push(target);
|
|
126
|
-
neighbours = neighbours.concat(map(index.find, pluck('source', incoming)));
|
|
127
|
-
relations = relations.concat(incoming);
|
|
128
|
-
}
|
|
129
|
-
}
|
|
130
|
-
return {
|
|
131
|
-
elements: uniq(elements),
|
|
132
|
-
neighbours: dropNested(neighbours),
|
|
133
|
-
relations: uniq(relations)
|
|
134
|
-
};
|
|
135
|
-
}
|
|
136
|
-
if (Expr.isOutgoing(expr)) {
|
|
137
|
-
const sources = evaluateElementExpression(index, expr.outgoing).elements;
|
|
138
|
-
for (const source of sources) {
|
|
139
|
-
const outgoing = index.filterRelations(isOutgoing(source.id));
|
|
140
|
-
if (outgoing.length > 0) {
|
|
141
|
-
elements.push(source);
|
|
142
|
-
neighbours = neighbours.concat(map(index.find, pluck('target', outgoing)));
|
|
143
|
-
relations = relations.concat(outgoing);
|
|
144
|
-
}
|
|
145
|
-
}
|
|
146
|
-
return {
|
|
147
|
-
elements: uniq(elements),
|
|
148
|
-
neighbours: dropNested(neighbours),
|
|
149
|
-
relations: uniq(relations)
|
|
150
|
-
};
|
|
151
|
-
}
|
|
152
|
-
if (Expr.isRelation(expr)) {
|
|
153
|
-
const isSourceWildcard = Expr.isWildcard(expr.source);
|
|
154
|
-
const isTargetWildcard = Expr.isWildcard(expr.target);
|
|
155
|
-
if (isSourceWildcard && !isTargetWildcard) {
|
|
156
|
-
return evaluateExpression(index, {
|
|
157
|
-
incoming: expr.target
|
|
158
|
-
}, rootElement);
|
|
159
|
-
}
|
|
160
|
-
if (!isSourceWildcard && isTargetWildcard) {
|
|
161
|
-
return evaluateExpression(index, {
|
|
162
|
-
outgoing: expr.source
|
|
163
|
-
}, rootElement);
|
|
164
|
-
}
|
|
165
|
-
const sources = evaluateElementExpression(index, expr.source).elements;
|
|
166
|
-
const targets = evaluateElementExpression(index, expr.target).elements;
|
|
167
|
-
for (const source of sources) {
|
|
168
|
-
for (const target of targets) {
|
|
169
|
-
if (isAncestor(source.id, target.id) || isAncestor(target.id, source.id)) {
|
|
170
|
-
continue;
|
|
171
|
-
}
|
|
172
|
-
const foundRelations = index.filterRelations(isBetween(source.id, target.id));
|
|
173
|
-
if (foundRelations.length > 0) {
|
|
174
|
-
relations = relations.concat(foundRelations);
|
|
175
|
-
neighbours.push(source, target);
|
|
176
|
-
}
|
|
177
|
-
}
|
|
178
|
-
}
|
|
179
|
-
return {
|
|
180
|
-
elements,
|
|
181
|
-
neighbours: uniq(neighbours),
|
|
182
|
-
relations: uniq(relations)
|
|
183
|
-
};
|
|
184
|
-
}
|
|
185
|
-
return evaluateElementExpression(index, expr, rootElement);
|
|
186
|
-
}
|