@likec4/core 0.6.3 → 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.d.ts +1 -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 → compute-element-view.d.ts} +2 -2
- package/dist/compute-view/compute-element-view.js +416 -0
- package/dist/compute-view/{compute-view.d.ts → compute.d.ts} +2 -2
- package/dist/compute-view/{compute-view.js → compute.js} +1 -1
- package/dist/compute-view/index.d.ts +2 -1
- package/dist/compute-view/index.js +1 -1
- package/dist/compute-view/utils/anyPossibleRelations.d.ts +1 -0
- package/dist/compute-view/utils/sortNodes.d.ts +1 -0
- package/dist/index.d.ts +4 -2
- package/dist/index.js +2 -1
- package/dist/model-index/{model-index.d.ts → ModelIndex.d.ts} +1 -0
- package/dist/model-index/{model-index.js → ModelIndex.js} +3 -3
- package/dist/model-index/index.d.ts +2 -1
- package/dist/model-index/index.js +1 -1
- package/dist/types/computed-view.d.ts +1 -0
- package/dist/types/diagram.d.ts +7 -0
- package/dist/types/element.d.ts +3 -2
- package/dist/types/expression.d.ts +1 -0
- package/dist/types/index.d.ts +1 -0
- package/dist/types/model.d.ts +1 -0
- package/dist/types/opaque.d.ts +1 -0
- package/dist/types/relation.d.ts +1 -0
- package/dist/types/view.d.ts +1 -0
- 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 +3 -0
- package/dist/utils/fqn.js +22 -1
- package/dist/utils/guards.d.ts +1 -0
- package/dist/utils/index.d.ts +2 -0
- package/dist/utils/index.js +1 -0
- package/dist/utils/relations.d.ts +3 -1
- package/dist/utils/relations.js +10 -4
- package/package.json +31 -21
- package/dist/compute-view/compute.element-view.js +0 -168
- package/dist/compute-view/utils/evaluate-expression.d.ts +0 -10
- package/dist/compute-view/utils/evaluate-expression.js +0 -186
package/dist/index.d.ts
CHANGED
|
@@ -1,4 +1,6 @@
|
|
|
1
|
-
export type *
|
|
2
|
-
export
|
|
1
|
+
export type * from './types';
|
|
2
|
+
export * from './compute-view';
|
|
3
3
|
export * from './utils';
|
|
4
4
|
export * from './model-index';
|
|
5
|
+
export * from './colors';
|
|
6
|
+
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.js
CHANGED
|
@@ -38,9 +38,9 @@ export class ModelIndex {
|
|
|
38
38
|
}
|
|
39
39
|
for (const { id, viewOf } of Object.values(views)) {
|
|
40
40
|
if (viewOf) {
|
|
41
|
-
const
|
|
42
|
-
|
|
43
|
-
index._defaultElementView.set(viewOf,
|
|
41
|
+
const viewsOf = index._defaultElementView.get(viewOf) ?? [];
|
|
42
|
+
viewsOf.push(id);
|
|
43
|
+
index._defaultElementView.set(viewOf, viewsOf);
|
|
44
44
|
}
|
|
45
45
|
}
|
|
46
46
|
return index;
|
|
@@ -1 +1,2 @@
|
|
|
1
|
-
export * from './
|
|
1
|
+
export * from './ModelIndex';
|
|
2
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
export * from './
|
|
1
|
+
export * from './ModelIndex';
|
package/dist/types/diagram.d.ts
CHANGED
|
@@ -24,4 +24,11 @@ export interface DiagramEdge extends ComputedEdge {
|
|
|
24
24
|
export interface DiagramView extends ComputedView<DiagramNode, DiagramEdge> {
|
|
25
25
|
width: number;
|
|
26
26
|
height: number;
|
|
27
|
+
boundingBox: {
|
|
28
|
+
x: number;
|
|
29
|
+
y: number;
|
|
30
|
+
width: number;
|
|
31
|
+
height: number;
|
|
32
|
+
};
|
|
27
33
|
}
|
|
34
|
+
//# sourceMappingURL=diagram.d.ts.map
|
package/dist/types/element.d.ts
CHANGED
|
@@ -2,8 +2,8 @@ import type { Opaque } from './opaque';
|
|
|
2
2
|
export type Fqn = Opaque<string, 'Fqn'>;
|
|
3
3
|
export declare function Fqn(name: string, parent?: Fqn | null): Fqn;
|
|
4
4
|
export type ElementKind = Opaque<string, 'ElementKind'>;
|
|
5
|
-
export type ThemeColor = 'primary' | 'secondary' | '
|
|
6
|
-
export type ElementShape = 'rectangle' | 'person' | 'browser' | 'cylinder' | 'storage' | 'queue';
|
|
5
|
+
export type ThemeColor = 'amber' | 'blue' | 'gray' | 'slate' | 'green' | 'indigo' | 'muted' | 'primary' | 'red' | 'secondary' | 'sky';
|
|
6
|
+
export type ElementShape = 'rectangle' | 'person' | 'browser' | 'mobile' | 'cylinder' | 'storage' | 'queue';
|
|
7
7
|
export declare const DefaultThemeColor: ThemeColor;
|
|
8
8
|
export declare const DefaultElementShape: ElementShape;
|
|
9
9
|
export interface ElementStyle {
|
|
@@ -24,3 +24,4 @@ export interface Element {
|
|
|
24
24
|
readonly shape?: ElementShape;
|
|
25
25
|
readonly color?: ThemeColor;
|
|
26
26
|
}
|
|
27
|
+
//# sourceMappingURL=element.d.ts.map
|
|
@@ -41,3 +41,4 @@ export type AnyRelationExpression = RelationExpr | InOutExpr | IncomingExpr | Ou
|
|
|
41
41
|
export declare function isAnyRelation(expr: Expression): expr is AnyRelationExpression;
|
|
42
42
|
export type Expression = ElementExpression | AnyRelationExpression;
|
|
43
43
|
export {};
|
|
44
|
+
//# sourceMappingURL=expression.d.ts.map
|
package/dist/types/index.d.ts
CHANGED
package/dist/types/model.d.ts
CHANGED
package/dist/types/opaque.d.ts
CHANGED
package/dist/types/relation.d.ts
CHANGED
package/dist/types/view.d.ts
CHANGED
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type { ComputedView } from '../types/computed-view';
|
|
2
|
+
type NodeLevelDepth = {
|
|
3
|
+
level: number;
|
|
4
|
+
depth: number;
|
|
5
|
+
};
|
|
6
|
+
export declare const computeNodeLevels: ({ nodes }: ComputedView) => Record<import("..").Fqn, NodeLevelDepth>;
|
|
7
|
+
export {};
|
|
8
|
+
//# sourceMappingURL=compute-node-levels.d.ts.map
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import invariant from 'tiny-invariant';
|
|
2
|
+
export const computeNodeLevels = ({ nodes }) => {
|
|
3
|
+
const nodeLevels = {};
|
|
4
|
+
const compute = (node, level) => {
|
|
5
|
+
let levels = nodeLevels[node.id];
|
|
6
|
+
if (levels) {
|
|
7
|
+
return levels;
|
|
8
|
+
}
|
|
9
|
+
if (node.children.length === 0) {
|
|
10
|
+
levels = { level, depth: 0 };
|
|
11
|
+
nodeLevels[node.id] = levels;
|
|
12
|
+
return levels;
|
|
13
|
+
}
|
|
14
|
+
let depth = 1;
|
|
15
|
+
for (const childId of node.children) {
|
|
16
|
+
const child = nodes.find(n => n.id === childId);
|
|
17
|
+
invariant(child, `Child ${childId} not found`);
|
|
18
|
+
const { depth: childDepth } = compute(child, level + 1);
|
|
19
|
+
depth = Math.max(childDepth + 1, depth);
|
|
20
|
+
}
|
|
21
|
+
levels = { level, depth };
|
|
22
|
+
nodeLevels[node.id] = levels;
|
|
23
|
+
return levels;
|
|
24
|
+
};
|
|
25
|
+
for (const node of nodes) {
|
|
26
|
+
if (!node.parent) {
|
|
27
|
+
compute(node, 0);
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
return nodeLevels;
|
|
31
|
+
};
|
package/dist/utils/fqn.d.ts
CHANGED
|
@@ -2,9 +2,12 @@ import type { Element, Fqn } from '../types';
|
|
|
2
2
|
export declare function nameFromFqn(fqn: Fqn): string;
|
|
3
3
|
export declare function isAncestor(...args: [ancestor: Fqn, another: Fqn] | [ancestor: Element, another: Element]): boolean;
|
|
4
4
|
export declare function isSameHierarchy(...args: [one: Fqn, another: Fqn] | [one: Element, another: Element]): boolean;
|
|
5
|
+
export declare function isDescendantOf(ancestors: Element[]): (e: Element) => boolean;
|
|
6
|
+
export declare function notDescendantOf(ancestors: Element[]): (e: Element) => boolean;
|
|
5
7
|
export declare function commonAncestor(first: Fqn, second: Fqn): Fqn | null;
|
|
6
8
|
export declare function parentFqn(fqn: Fqn): Fqn | null;
|
|
7
9
|
export declare const compareFqnHierarchically: (a: string, b: string) => number;
|
|
8
10
|
export declare const compareByFqnHierarchically: <T extends {
|
|
9
11
|
id: Fqn;
|
|
10
12
|
}>(a: T, b: T) => number;
|
|
13
|
+
//# sourceMappingURL=fqn.d.ts.map
|
package/dist/utils/fqn.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { anyPass } from 'rambdax';
|
|
1
2
|
import { isString } from './guards';
|
|
2
3
|
export function nameFromFqn(fqn) {
|
|
3
4
|
const lastDot = fqn.lastIndexOf('.');
|
|
@@ -18,7 +19,26 @@ export function isSameHierarchy(...args) {
|
|
|
18
19
|
const another = isString(args[1]) ? args[1] : args[1].id;
|
|
19
20
|
return one === another || another.startsWith(one + '.') || one.startsWith(another + '.');
|
|
20
21
|
}
|
|
22
|
+
export function isDescendantOf(ancestors) {
|
|
23
|
+
const predicates = ancestors.flatMap(a => [
|
|
24
|
+
(e) => e.id === a.id,
|
|
25
|
+
(e) => isAncestor(a, e)
|
|
26
|
+
]);
|
|
27
|
+
return anyPass(predicates);
|
|
28
|
+
}
|
|
29
|
+
export function notDescendantOf(ancestors) {
|
|
30
|
+
const isDescendant = isDescendantOf(ancestors);
|
|
31
|
+
return (e) => !isDescendant(e);
|
|
32
|
+
}
|
|
21
33
|
export function commonAncestor(first, second) {
|
|
34
|
+
const parentA = parentFqn(first);
|
|
35
|
+
const parentB = parentFqn(second);
|
|
36
|
+
if (parentA === parentB) {
|
|
37
|
+
return parentA;
|
|
38
|
+
}
|
|
39
|
+
if (!parentA || !parentB) {
|
|
40
|
+
return null;
|
|
41
|
+
}
|
|
22
42
|
const a = first.split('.');
|
|
23
43
|
const b = second.split('.');
|
|
24
44
|
let ancestor = null;
|
|
@@ -40,7 +60,8 @@ export const compareFqnHierarchically = (a, b) => {
|
|
|
40
60
|
const depthA = a.split('.').length;
|
|
41
61
|
const depthB = b.split('.').length;
|
|
42
62
|
if (depthA === depthB) {
|
|
43
|
-
return a.localeCompare(b)
|
|
63
|
+
// return a.localeCompare(b)
|
|
64
|
+
return 0;
|
|
44
65
|
}
|
|
45
66
|
else {
|
|
46
67
|
return depthA - depthB;
|
package/dist/utils/guards.d.ts
CHANGED
package/dist/utils/index.d.ts
CHANGED
package/dist/utils/index.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { Fqn } from '../types';
|
|
1
|
+
import type { Fqn, Element } from '../types';
|
|
2
2
|
type Relation = {
|
|
3
3
|
source: Fqn;
|
|
4
4
|
target: Fqn;
|
|
@@ -13,4 +13,6 @@ export declare const isAnyBetween: (source: Fqn, target: Fqn) => import("rambdax
|
|
|
13
13
|
export declare const isIncoming: (target: Fqn) => (rel: Relation) => boolean;
|
|
14
14
|
export declare const isOutgoing: (source: Fqn) => (rel: Relation) => boolean;
|
|
15
15
|
export declare const isAnyInOut: (source: Fqn) => import("rambdax").Predicate<Relation>;
|
|
16
|
+
export declare const hasRelation: (rel: Relation) => (element: Element) => boolean;
|
|
16
17
|
export {};
|
|
18
|
+
//# sourceMappingURL=relations.d.ts.map
|
package/dist/utils/relations.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { either } from 'rambdax';
|
|
2
|
-
import { compareFqnHierarchically } from './fqn';
|
|
2
|
+
import { compareFqnHierarchically, isAncestor } from './fqn';
|
|
3
3
|
export const compareRelations = (a, b) => {
|
|
4
4
|
return (compareFqnHierarchically(a.source, b.source) || compareFqnHierarchically(a.target, b.target));
|
|
5
5
|
};
|
|
@@ -13,7 +13,8 @@ export const isBetween = (source, target) => {
|
|
|
13
13
|
const sourcePrefix = source + '.';
|
|
14
14
|
const targetPrefix = target + '.';
|
|
15
15
|
return (rel) => {
|
|
16
|
-
return ((rel.source
|
|
16
|
+
return ((rel.source === source || (rel.source + '.').startsWith(sourcePrefix)) &&
|
|
17
|
+
(rel.target === target || (rel.target + '.').startsWith(targetPrefix)));
|
|
17
18
|
};
|
|
18
19
|
};
|
|
19
20
|
export const isAnyBetween = (source, target) => {
|
|
@@ -22,15 +23,20 @@ export const isAnyBetween = (source, target) => {
|
|
|
22
23
|
export const isIncoming = (target) => {
|
|
23
24
|
const targetPrefix = target + '.';
|
|
24
25
|
return (rel) => {
|
|
25
|
-
return (!(rel.source + '.').startsWith(targetPrefix) && (rel.target + '.').startsWith(targetPrefix));
|
|
26
|
+
return (!(rel.source + '.').startsWith(targetPrefix) && (rel.target === target || (rel.target + '.').startsWith(targetPrefix)));
|
|
26
27
|
};
|
|
27
28
|
};
|
|
28
29
|
export const isOutgoing = (source) => {
|
|
29
30
|
const sourcePrefix = source + '.';
|
|
30
31
|
return (rel) => {
|
|
31
|
-
return ((rel.source + '.').startsWith(sourcePrefix) && !(rel.target + '.').startsWith(sourcePrefix));
|
|
32
|
+
return ((rel.source === source || (rel.source + '.').startsWith(sourcePrefix)) && !(rel.target + '.').startsWith(sourcePrefix));
|
|
32
33
|
};
|
|
33
34
|
};
|
|
34
35
|
export const isAnyInOut = (source) => {
|
|
35
36
|
return either(isIncoming(source), isOutgoing(source));
|
|
36
37
|
};
|
|
38
|
+
export const hasRelation = (rel) => {
|
|
39
|
+
return (element) => {
|
|
40
|
+
return isAncestor(rel.source, element.id) || isAncestor(rel.target, element.id);
|
|
41
|
+
};
|
|
42
|
+
};
|
package/package.json
CHANGED
|
@@ -1,12 +1,15 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@likec4/core",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.18.0",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"bugs": "https://github.com/likec4/likec4/issues",
|
|
6
|
-
"homepage": "https://
|
|
6
|
+
"homepage": "https://likec4.dev",
|
|
7
7
|
"author": "Denis Davydkov <denis@davydkov.com>",
|
|
8
8
|
"files": [
|
|
9
|
-
"dist"
|
|
9
|
+
"dist",
|
|
10
|
+
"!dist/__test__",
|
|
11
|
+
"!**/*.spec.*",
|
|
12
|
+
"!**/*.map"
|
|
10
13
|
],
|
|
11
14
|
"repository": {
|
|
12
15
|
"type": "git",
|
|
@@ -14,77 +17,84 @@
|
|
|
14
17
|
"directory": "packages/core"
|
|
15
18
|
},
|
|
16
19
|
"scripts": {
|
|
17
|
-
"compile": "tsc --
|
|
18
|
-
"build:release": "tsc -p tsconfig.esm.json",
|
|
20
|
+
"compile": "tsc --noEmit",
|
|
19
21
|
"build": "tsc",
|
|
20
22
|
"dev": "tsc --watch",
|
|
21
23
|
"lint": "run -T eslint src/ --fix",
|
|
22
|
-
"test": "vitest run",
|
|
23
|
-
"test:watch": "vitest",
|
|
24
|
+
"test": "run -T vitest run",
|
|
25
|
+
"test:watch": "run -T vitest",
|
|
24
26
|
"clean": "run -T rimraf dist"
|
|
25
27
|
},
|
|
26
|
-
"
|
|
28
|
+
"module": "./dist/index.js",
|
|
27
29
|
"types": "./dist/index.d.ts",
|
|
28
30
|
"type": "module",
|
|
29
31
|
"exports": {
|
|
30
32
|
".": {
|
|
31
33
|
"types": "./dist/index.d.ts",
|
|
32
34
|
"import": "./dist/index.js",
|
|
33
|
-
"
|
|
35
|
+
"default": "./dist/index.js"
|
|
34
36
|
},
|
|
35
37
|
"./types": {
|
|
36
38
|
"types": "./dist/types/index.d.ts",
|
|
37
39
|
"import": "./dist/types/index.js",
|
|
38
|
-
"
|
|
40
|
+
"default": "./dist/types/index.js"
|
|
41
|
+
},
|
|
42
|
+
"./colors": {
|
|
43
|
+
"types": "./dist/colors.d.ts",
|
|
44
|
+
"import": "./dist/colors.js",
|
|
45
|
+
"default": "./dist/colors.js"
|
|
39
46
|
},
|
|
40
47
|
"./utils": {
|
|
41
48
|
"types": "./dist/utils/index.d.ts",
|
|
42
49
|
"import": "./dist/utils/index.js",
|
|
43
|
-
"
|
|
50
|
+
"default": "./dist/utils/index.js"
|
|
44
51
|
},
|
|
45
52
|
"./compute-view": {
|
|
46
53
|
"types": "./dist/compute-view/index.d.ts",
|
|
47
54
|
"import": "./dist/compute-view/index.js",
|
|
48
|
-
"
|
|
55
|
+
"default": "./dist/compute-view/index.js"
|
|
49
56
|
}
|
|
50
57
|
},
|
|
51
58
|
"sideEffects": false,
|
|
52
59
|
"publishConfig": {
|
|
53
60
|
"registry": "https://registry.npmjs.org",
|
|
54
61
|
"access": "public",
|
|
55
|
-
"
|
|
62
|
+
"module": "./dist/index.js",
|
|
56
63
|
"types": "./dist/index.d.ts",
|
|
57
64
|
"exports": {
|
|
58
65
|
".": {
|
|
59
66
|
"types": "./dist/index.d.ts",
|
|
60
67
|
"import": "./dist/index.js",
|
|
61
|
-
"
|
|
68
|
+
"default": "./dist/index.js"
|
|
62
69
|
},
|
|
63
70
|
"./types": {
|
|
64
71
|
"types": "./dist/types/index.d.ts",
|
|
65
72
|
"import": "./dist/types/index.js",
|
|
66
|
-
"
|
|
73
|
+
"default": "./dist/types/index.js"
|
|
74
|
+
},
|
|
75
|
+
"./colors": {
|
|
76
|
+
"types": "./dist/colors.d.ts",
|
|
77
|
+
"import": "./dist/colors.js",
|
|
78
|
+
"default": "./dist/colors.js"
|
|
67
79
|
},
|
|
68
80
|
"./utils": {
|
|
69
81
|
"types": "./dist/utils/index.d.ts",
|
|
70
82
|
"import": "./dist/utils/index.js",
|
|
71
|
-
"
|
|
83
|
+
"default": "./dist/utils/index.js"
|
|
72
84
|
},
|
|
73
85
|
"./compute-view": {
|
|
74
86
|
"types": "./dist/compute-view/index.d.ts",
|
|
75
87
|
"import": "./dist/compute-view/index.js",
|
|
76
|
-
"
|
|
88
|
+
"default": "./dist/compute-view/index.js"
|
|
77
89
|
}
|
|
78
90
|
}
|
|
79
91
|
},
|
|
80
92
|
"dependencies": {
|
|
81
93
|
"@dagrejs/graphlib": "^2.1.12",
|
|
82
|
-
"rambdax": "^9.1.
|
|
94
|
+
"rambdax": "^9.1.1",
|
|
83
95
|
"tiny-invariant": "^1.3.1"
|
|
84
96
|
},
|
|
85
97
|
"devDependencies": {
|
|
86
|
-
"typescript": "^5.
|
|
87
|
-
"vite": "^4.2.2",
|
|
88
|
-
"vitest": "^0.30.1"
|
|
98
|
+
"typescript": "^5.1.3"
|
|
89
99
|
}
|
|
90
100
|
}
|
|
@@ -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 [...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,10 +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 {};
|