likec4 0.37.1 → 0.40.0-build.10
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/bin/likec4.mjs +3 -0
- package/dist/@likec4/core/colors.js +104 -0
- package/dist/@likec4/core/compute-view/EdgeBuilder.js +30 -0
- package/dist/@likec4/core/compute-view/compute-ctx.js +100 -0
- package/dist/@likec4/core/compute-view/compute-element-view.js +98 -0
- package/dist/@likec4/core/compute-view/compute-predicates.js +324 -0
- package/dist/@likec4/core/compute-view/compute.js +36 -0
- package/dist/@likec4/core/compute-view/index.js +4 -0
- package/dist/@likec4/core/compute-view/resolve-extended-views.js +41 -0
- package/dist/@likec4/core/compute-view/resolve-relative-paths.js +76 -0
- package/dist/@likec4/core/compute-view/utils/anyPossibleRelations.js +12 -0
- package/dist/@likec4/core/compute-view/utils/applyViewRuleStyles.js +50 -0
- package/dist/@likec4/core/compute-view/utils/sortNodes.js +37 -0
- package/dist/@likec4/core/errors/index.js +97 -0
- package/dist/@likec4/core/index.js +6 -0
- package/dist/@likec4/core/model-index/ModelIndex.js +127 -0
- package/dist/@likec4/core/model-index/index.js +1 -0
- package/dist/@likec4/core/types/_common.js +0 -0
- package/dist/@likec4/core/types/computed-view.js +0 -0
- package/dist/@likec4/core/types/diagram.js +0 -0
- package/dist/@likec4/core/types/element.js +5 -0
- package/dist/@likec4/core/types/expression.js +30 -0
- package/dist/@likec4/core/types/index.js +11 -0
- package/dist/@likec4/core/types/model.js +0 -0
- package/dist/@likec4/core/types/opaque.js +0 -0
- package/dist/@likec4/core/types/relation.js +0 -0
- package/dist/@likec4/core/types/theme.js +0 -0
- package/dist/@likec4/core/types/view.js +15 -0
- package/dist/@likec4/core/utils/compute-node-levels.js +31 -0
- package/dist/@likec4/core/utils/fqn.js +66 -0
- package/dist/@likec4/core/utils/guards.js +6 -0
- package/dist/@likec4/core/utils/index.js +4 -0
- package/dist/@likec4/core/utils/relations.js +50 -0
- package/dist/@likec4/diagrams/components/EmbeddedDiagram.js +77 -0
- package/dist/@likec4/diagrams/components/FullscreenDiagramBrowser.js +52 -0
- package/dist/@likec4/diagrams/components/index.js +4 -0
- package/dist/@likec4/diagrams/components/primitives/fullscreen/CloseButton.js +43 -0
- package/dist/@likec4/diagrams/components/primitives/fullscreen/FullscreenDiagram.js +116 -0
- package/dist/@likec4/diagrams/components/primitives/fullscreen/FullscreenDiagramTitle.js +32 -0
- package/dist/@likec4/diagrams/components/primitives/index.js +3 -0
- package/dist/@likec4/diagrams/components/primitives/responsive/ResponsiveDiagram.js +42 -0
- package/dist/@likec4/diagrams/components/types.js +0 -0
- package/dist/@likec4/diagrams/diagram/Diagram.js +298 -0
- package/dist/@likec4/diagrams/diagram/Edges.js +115 -0
- package/dist/@likec4/diagrams/diagram/Nodes.js +176 -0
- package/dist/@likec4/diagrams/diagram/icons/BrainIcon.js +20 -0
- package/dist/@likec4/diagrams/diagram/icons/ExternalLink.js +91 -0
- package/dist/@likec4/diagrams/diagram/icons/index.js +2 -0
- package/dist/@likec4/diagrams/diagram/index.js +2 -0
- package/dist/@likec4/diagrams/diagram/shapes/Browser.js +49 -0
- package/dist/@likec4/diagrams/diagram/shapes/Compound.js +48 -0
- package/dist/@likec4/diagrams/diagram/shapes/Cylinder.js +57 -0
- package/dist/@likec4/diagrams/diagram/shapes/Edge.js +63 -0
- package/dist/@likec4/diagrams/diagram/shapes/Mobile.js +33 -0
- package/dist/@likec4/diagrams/diagram/shapes/NodeIcon.js +28 -0
- package/dist/@likec4/diagrams/diagram/shapes/NodeLabel.js +59 -0
- package/dist/@likec4/diagrams/diagram/shapes/Person.js +42 -0
- package/dist/@likec4/diagrams/diagram/shapes/Queue.js +58 -0
- package/dist/@likec4/diagrams/diagram/shapes/Rectangle.js +20 -0
- package/dist/@likec4/diagrams/diagram/shapes/index.js +7 -0
- package/dist/@likec4/diagrams/diagram/shapes/types.js +0 -0
- package/dist/@likec4/diagrams/diagram/shapes/utils.js +12 -0
- package/dist/@likec4/diagrams/diagram/springs.js +57 -0
- package/dist/@likec4/diagrams/diagram/state/atoms.js +71 -0
- package/dist/@likec4/diagrams/diagram/state/gestures.js +19 -0
- package/dist/@likec4/diagrams/diagram/state/hooks.js +28 -0
- package/dist/@likec4/diagrams/diagram/state/index.js +3 -0
- package/dist/@likec4/diagrams/diagram/state/provider.js +7 -0
- package/dist/@likec4/diagrams/diagram/types.js +0 -0
- package/dist/@likec4/diagrams/hooks/index.js +4 -0
- package/dist/@likec4/diagrams/hooks/useDarkMode.js +5 -0
- package/dist/@likec4/diagrams/hooks/useDiagramRef.js +21 -0
- package/dist/@likec4/diagrams/hooks/useImageLoader.js +64 -0
- package/dist/@likec4/diagrams/hooks/useViewIdFromHash.js +87 -0
- package/dist/@likec4/diagrams/index.js +4 -0
- package/dist/@likec4/diagrams/konva-html.js +74 -0
- package/dist/@likec4/diagrams/konva-portal.js +34 -0
- package/dist/@likec4/diagrams/konva.js +22 -0
- package/dist/@likec4/diagrams/likec4.js +54 -0
- package/dist/__app__/favicon.svg +6 -0
- package/dist/__app__/index.html +14 -0
- package/dist/__app__/likec4.css +85 -0
- package/dist/__app__/postcss.config.cjs +11 -0
- package/dist/__app__/robots.txt +2 -0
- package/dist/__app__/src/App.tsx +37 -0
- package/dist/__app__/src/components/DiagramNotFound.tsx +30 -0
- package/dist/__app__/src/components/ThemePanelToggle.tsx +15 -0
- package/dist/__app__/src/components/index.ts +4 -0
- package/dist/__app__/src/components/sidebar/DiagramsTree.module.css +83 -0
- package/dist/__app__/src/components/sidebar/DiagramsTree.tsx +77 -0
- package/dist/__app__/src/components/sidebar/Sidebar.tsx +67 -0
- package/dist/__app__/src/components/sidebar/styles.module.css +85 -0
- package/dist/__app__/src/components/view-page/ShareDialog.tsx +148 -0
- package/dist/__app__/src/components/view-page/ViewActionsToolbar.tsx +76 -0
- package/dist/__app__/src/data/atoms.ts +108 -0
- package/dist/__app__/src/data/hooks.ts +16 -0
- package/dist/__app__/src/data/index.ts +1 -0
- package/dist/__app__/src/data/likec4.d.ts +5 -0
- package/dist/__app__/src/data/sidebar-diagram-tree.ts +52 -0
- package/dist/__app__/src/main.tsx +12 -0
- package/dist/__app__/src/pages/export.module.css +4 -0
- package/dist/__app__/src/pages/export.page.tsx +37 -0
- package/dist/__app__/src/pages/index.module.css +11 -0
- package/dist/__app__/src/pages/index.page.tsx +103 -0
- package/dist/__app__/src/pages/index.ts +3 -0
- package/dist/__app__/src/pages/view.page.tsx +67 -0
- package/dist/__app__/src/router.ts +67 -0
- package/dist/__app__/src/utils/index.ts +1 -0
- package/dist/__app__/src/utils/utils.ts +6 -0
- package/dist/__app__/tailwind.config.cjs +19 -0
- package/dist/__app__/tsconfig.json +28 -0
- package/dist/cli/index.js +55755 -0
- package/package.json +75 -9
package/bin/likec4.mjs
ADDED
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
const blue = {
|
|
2
|
+
// fill: colors.blue[500],
|
|
3
|
+
// stroke: colors.blue[600],
|
|
4
|
+
// hiContrast: colors.blue[50],
|
|
5
|
+
// loContrast: colors.blue[200],
|
|
6
|
+
fill: "#3b82f6",
|
|
7
|
+
stroke: "#2563eb",
|
|
8
|
+
hiContrast: "#eff6ff",
|
|
9
|
+
loContrast: "#bfdbfe"
|
|
10
|
+
};
|
|
11
|
+
const sky = {
|
|
12
|
+
// fill: colors.sky[600],
|
|
13
|
+
// stroke: colors.sky[700],
|
|
14
|
+
// hiContrast: colors.sky[50],
|
|
15
|
+
// loContrast: colors.sky[100],
|
|
16
|
+
fill: "#0284c7",
|
|
17
|
+
stroke: "#0369a1",
|
|
18
|
+
hiContrast: "#f0f9ff",
|
|
19
|
+
loContrast: "#e0f2fe"
|
|
20
|
+
};
|
|
21
|
+
const slate = {
|
|
22
|
+
// fill: colors.slate[500],
|
|
23
|
+
// stroke: colors.slate[600],
|
|
24
|
+
// hiContrast: colors.slate[50],
|
|
25
|
+
// loContrast: colors.slate[200],
|
|
26
|
+
fill: "#64748b",
|
|
27
|
+
stroke: "#475569",
|
|
28
|
+
hiContrast: "#f8fafc",
|
|
29
|
+
loContrast: "#e2e8f0"
|
|
30
|
+
};
|
|
31
|
+
export const RelationColors = {
|
|
32
|
+
lineColor: "#b1b1b1",
|
|
33
|
+
labelColor: "#b1b1b1"
|
|
34
|
+
};
|
|
35
|
+
export const Colors = {
|
|
36
|
+
primary: blue,
|
|
37
|
+
blue,
|
|
38
|
+
secondary: sky,
|
|
39
|
+
sky,
|
|
40
|
+
muted: slate,
|
|
41
|
+
slate,
|
|
42
|
+
gray: {
|
|
43
|
+
// fill: colors.neutral[500],
|
|
44
|
+
// stroke: colors.neutral[600],
|
|
45
|
+
// hiContrast: colors.neutral[50],
|
|
46
|
+
// loContrast: colors.neutral[200],
|
|
47
|
+
fill: "#737373",
|
|
48
|
+
stroke: "#525252",
|
|
49
|
+
hiContrast: "#fafafa",
|
|
50
|
+
loContrast: "#e5e5e5"
|
|
51
|
+
},
|
|
52
|
+
red: {
|
|
53
|
+
// fill: colors.red[500],
|
|
54
|
+
// stroke: colors.red[600],
|
|
55
|
+
// hiContrast: colors.red[50],
|
|
56
|
+
// loContrast: colors.red[200],
|
|
57
|
+
fill: "#b54548",
|
|
58
|
+
stroke: "#8c333a",
|
|
59
|
+
// hiContrast: '#fef2f2',
|
|
60
|
+
// loContrast: '#fecaca',
|
|
61
|
+
// hiContrast: '#191111', // colors.gray[900],
|
|
62
|
+
// loContrast: '#3b1219' // colors.gray[800],
|
|
63
|
+
hiContrast: "#f8fafc",
|
|
64
|
+
// hiContrast: '#f8fafc',
|
|
65
|
+
// loContrast: '#fdd8d8' // radix black red 12
|
|
66
|
+
loContrast: "#F9C6C6"
|
|
67
|
+
},
|
|
68
|
+
green: {
|
|
69
|
+
fill: "#428a4f",
|
|
70
|
+
stroke: "#2d5d39",
|
|
71
|
+
hiContrast: "#f8fafc",
|
|
72
|
+
loContrast: "#c2f0c2"
|
|
73
|
+
},
|
|
74
|
+
amber: {
|
|
75
|
+
// fill: colors.amber[600],
|
|
76
|
+
// stroke: colors.amber[700],
|
|
77
|
+
// hiContrast: colors.amber[50],
|
|
78
|
+
// loContrast: colors.amber[200],
|
|
79
|
+
fill: "#d97706",
|
|
80
|
+
stroke: "#b45309",
|
|
81
|
+
// hiContrast: '#fffbeb',
|
|
82
|
+
// loContrast: '#fde68a',
|
|
83
|
+
hiContrast: "#f8fafc",
|
|
84
|
+
// colors.gray[900],
|
|
85
|
+
loContrast: "#ffe0c2"
|
|
86
|
+
// colors.gray[800],
|
|
87
|
+
},
|
|
88
|
+
indigo: {
|
|
89
|
+
// fill: colors.indigo[500],
|
|
90
|
+
// stroke: colors.indigo[600],
|
|
91
|
+
// hiContrast: colors.indigo[50],
|
|
92
|
+
// loContrast: colors.indigo[200],
|
|
93
|
+
fill: "#6366f1",
|
|
94
|
+
stroke: "#4f46e5",
|
|
95
|
+
hiContrast: "#eef2ff",
|
|
96
|
+
loContrast: "#c7d2fe"
|
|
97
|
+
}
|
|
98
|
+
};
|
|
99
|
+
export const defaultTheme = {
|
|
100
|
+
font: "Helvetica",
|
|
101
|
+
shadow: "#0a0a0a",
|
|
102
|
+
relation: RelationColors,
|
|
103
|
+
colors: Colors
|
|
104
|
+
};
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { keys, pluck } from "rambdax";
|
|
2
|
+
import { commonAncestor, compareRelations } from "../utils/index.js";
|
|
3
|
+
export class EdgeBuilder {
|
|
4
|
+
_relationsObj = {};
|
|
5
|
+
add(source, target, relation) {
|
|
6
|
+
const bySource = this._relationsObj[source] ?? {};
|
|
7
|
+
const relations = bySource[target] ?? [];
|
|
8
|
+
relations.push(relation);
|
|
9
|
+
bySource[target] = relations;
|
|
10
|
+
this._relationsObj[source] = bySource;
|
|
11
|
+
return this;
|
|
12
|
+
}
|
|
13
|
+
build() {
|
|
14
|
+
return keys(this._relationsObj).flatMap((source) => {
|
|
15
|
+
const targets = this._relationsObj[source] ?? {};
|
|
16
|
+
return keys(targets).map((target) => {
|
|
17
|
+
const relations = (targets[target] ?? []).sort(compareRelations);
|
|
18
|
+
const label = relations.find((r) => r.title !== "")?.title ?? null;
|
|
19
|
+
return {
|
|
20
|
+
id: `${source}:${target}`,
|
|
21
|
+
parent: commonAncestor(source, target),
|
|
22
|
+
source,
|
|
23
|
+
target,
|
|
24
|
+
label,
|
|
25
|
+
relations: pluck("id", relations)
|
|
26
|
+
};
|
|
27
|
+
});
|
|
28
|
+
}).sort(compareRelations).reverse();
|
|
29
|
+
}
|
|
30
|
+
}
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
import { difference } from "rambdax";
|
|
2
|
+
import { Expr, isStrictElementView, isViewRuleExpression } from "../types/index.js";
|
|
3
|
+
import {
|
|
4
|
+
excludeElementKindOrTag,
|
|
5
|
+
excludeElementRef,
|
|
6
|
+
excludeInOutExpr,
|
|
7
|
+
excludeIncomingExpr,
|
|
8
|
+
excludeOutgoingExpr,
|
|
9
|
+
excludeRelationExpr,
|
|
10
|
+
excludeWildcardRef,
|
|
11
|
+
includeElementKindOrTag,
|
|
12
|
+
includeElementRef,
|
|
13
|
+
includeInOutExpr,
|
|
14
|
+
includeIncomingExpr,
|
|
15
|
+
includeOutgoingExpr,
|
|
16
|
+
includeRelationExpr,
|
|
17
|
+
includeWildcardRef
|
|
18
|
+
} from "./compute-predicates.js";
|
|
19
|
+
import { nonexhaustive } from "../errors/index.js";
|
|
20
|
+
export class ComputeCtx {
|
|
21
|
+
constructor(index, root, elements = /* @__PURE__ */ new Set(), relations = /* @__PURE__ */ new Set(), implicits = /* @__PURE__ */ new Set()) {
|
|
22
|
+
this.index = index;
|
|
23
|
+
this.root = root;
|
|
24
|
+
this.elements = elements;
|
|
25
|
+
this.relations = relations;
|
|
26
|
+
this.implicits = implicits;
|
|
27
|
+
this.allElements = /* @__PURE__ */ new Set([...this.elements, ...this.implicits]);
|
|
28
|
+
}
|
|
29
|
+
allElements;
|
|
30
|
+
include({ elements, relations, implicits }) {
|
|
31
|
+
return new ComputeCtx(
|
|
32
|
+
this.index,
|
|
33
|
+
this.root,
|
|
34
|
+
elements ? /* @__PURE__ */ new Set([...this.elements, ...elements]) : this.elements,
|
|
35
|
+
relations ? /* @__PURE__ */ new Set([...this.relations, ...relations]) : this.relations,
|
|
36
|
+
implicits ? /* @__PURE__ */ new Set([...this.implicits, ...implicits]) : this.implicits
|
|
37
|
+
);
|
|
38
|
+
}
|
|
39
|
+
exclude({ elements, relations, implicits }) {
|
|
40
|
+
let newImplicits = implicits ? new Set(difference([...this.implicits], implicits)) : this.implicits;
|
|
41
|
+
if (elements) {
|
|
42
|
+
newImplicits = new Set(difference([...newImplicits], elements));
|
|
43
|
+
}
|
|
44
|
+
return new ComputeCtx(
|
|
45
|
+
this.index,
|
|
46
|
+
this.root,
|
|
47
|
+
elements ? new Set(difference([...this.elements], elements)) : this.elements,
|
|
48
|
+
relations ? new Set(difference([...this.relations], relations)) : this.relations,
|
|
49
|
+
newImplicits
|
|
50
|
+
);
|
|
51
|
+
}
|
|
52
|
+
processViewRules(viewRules) {
|
|
53
|
+
let ctx = this;
|
|
54
|
+
for (const { isInclude, exprs } of viewRules) {
|
|
55
|
+
for (const expr of exprs) {
|
|
56
|
+
if (Expr.isElementKindExpr(expr) || Expr.isElementTagExpr(expr)) {
|
|
57
|
+
ctx = isInclude ? includeElementKindOrTag(ctx, expr) : excludeElementKindOrTag(ctx, expr);
|
|
58
|
+
continue;
|
|
59
|
+
}
|
|
60
|
+
if (Expr.isElementRef(expr)) {
|
|
61
|
+
ctx = isInclude ? includeElementRef(ctx, expr) : excludeElementRef(ctx, expr);
|
|
62
|
+
continue;
|
|
63
|
+
}
|
|
64
|
+
if (Expr.isWildcard(expr)) {
|
|
65
|
+
ctx = isInclude ? includeWildcardRef(ctx, expr) : excludeWildcardRef(ctx, expr);
|
|
66
|
+
continue;
|
|
67
|
+
}
|
|
68
|
+
if (Expr.isIncoming(expr)) {
|
|
69
|
+
ctx = isInclude ? includeIncomingExpr(ctx, expr) : excludeIncomingExpr(ctx, expr);
|
|
70
|
+
continue;
|
|
71
|
+
}
|
|
72
|
+
if (Expr.isOutgoing(expr)) {
|
|
73
|
+
ctx = isInclude ? includeOutgoingExpr(ctx, expr) : excludeOutgoingExpr(ctx, expr);
|
|
74
|
+
continue;
|
|
75
|
+
}
|
|
76
|
+
if (Expr.isInOut(expr)) {
|
|
77
|
+
ctx = isInclude ? includeInOutExpr(ctx, expr) : excludeInOutExpr(ctx, expr);
|
|
78
|
+
continue;
|
|
79
|
+
}
|
|
80
|
+
if (Expr.isRelation(expr)) {
|
|
81
|
+
ctx = isInclude ? includeRelationExpr(ctx, expr) : excludeRelationExpr(ctx, expr);
|
|
82
|
+
continue;
|
|
83
|
+
}
|
|
84
|
+
nonexhaustive(expr);
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
return ctx;
|
|
88
|
+
}
|
|
89
|
+
static create(view, index) {
|
|
90
|
+
const rootElement = isStrictElementView(view) ? view.viewOf : null;
|
|
91
|
+
let ctx = new ComputeCtx(index, rootElement);
|
|
92
|
+
const rulesInclude = view.rules.filter(isViewRuleExpression);
|
|
93
|
+
if (rootElement && rulesInclude.length == 0) {
|
|
94
|
+
ctx = ctx.include({
|
|
95
|
+
elements: [index.find(rootElement)]
|
|
96
|
+
});
|
|
97
|
+
}
|
|
98
|
+
return ctx.processViewRules(rulesInclude);
|
|
99
|
+
}
|
|
100
|
+
}
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
import { allPass, find } from "remeda";
|
|
2
|
+
import { nonNullable } from "../errors/index.js";
|
|
3
|
+
import {
|
|
4
|
+
DefaultElementShape,
|
|
5
|
+
DefaultThemeColor,
|
|
6
|
+
isViewRuleAutoLayout,
|
|
7
|
+
isViewRuleStyle
|
|
8
|
+
} from "../types/index.js";
|
|
9
|
+
import { compareByFqnHierarchically, isAncestor, isSameHierarchy, parentFqn } from "../utils/index.js";
|
|
10
|
+
import { EdgeBuilder } from "./EdgeBuilder.js";
|
|
11
|
+
import { ComputeCtx } from "./compute-ctx.js";
|
|
12
|
+
import { applyViewRuleStyles } from "./utils/applyViewRuleStyles.js";
|
|
13
|
+
import { sortNodes } from "./utils/sortNodes.js";
|
|
14
|
+
function reduceToMap(elementsIterator) {
|
|
15
|
+
return Array.from(elementsIterator).sort(compareByFqnHierarchically).reduce((map, { id, color, shape, ...el }) => {
|
|
16
|
+
let parent = parentFqn(id);
|
|
17
|
+
let level = 0;
|
|
18
|
+
while (parent) {
|
|
19
|
+
if (map.has(parent)) {
|
|
20
|
+
break;
|
|
21
|
+
}
|
|
22
|
+
parent = parentFqn(parent);
|
|
23
|
+
}
|
|
24
|
+
if (parent) {
|
|
25
|
+
const parentNd = nonNullable(map.get(parent));
|
|
26
|
+
parentNd.children.push(id);
|
|
27
|
+
level = parentNd.level + 1;
|
|
28
|
+
}
|
|
29
|
+
const node = {
|
|
30
|
+
...el,
|
|
31
|
+
id,
|
|
32
|
+
parent,
|
|
33
|
+
level,
|
|
34
|
+
color: color ?? DefaultThemeColor,
|
|
35
|
+
shape: shape ?? DefaultElementShape,
|
|
36
|
+
children: [],
|
|
37
|
+
inEdges: [],
|
|
38
|
+
outEdges: []
|
|
39
|
+
};
|
|
40
|
+
map.set(id, node);
|
|
41
|
+
return map;
|
|
42
|
+
}, /* @__PURE__ */ new Map());
|
|
43
|
+
}
|
|
44
|
+
const keepOriginalSortFromView = (_nodes, ctx) => {
|
|
45
|
+
const nodes = [...ctx.allElements].flatMap((e) => _nodes.get(e.id) || []);
|
|
46
|
+
for (const node of nodes) {
|
|
47
|
+
node.children = nodes.flatMap((n) => n.parent === node.id ? n.id : []);
|
|
48
|
+
}
|
|
49
|
+
return nodes;
|
|
50
|
+
};
|
|
51
|
+
export function computeElementView(view, index) {
|
|
52
|
+
const ctx = ComputeCtx.create(view, index);
|
|
53
|
+
const leafsFirst = [...ctx.allElements].sort((a, b) => -1 * compareByFqnHierarchically(a, b));
|
|
54
|
+
const elementsWithRelations = /* @__PURE__ */ new Set();
|
|
55
|
+
const edgeBuilder = new EdgeBuilder();
|
|
56
|
+
const anscestorOf = (id) => (e) => e.id === id || isAncestor(e.id, id);
|
|
57
|
+
const sortedRelations = [...ctx.relations];
|
|
58
|
+
for (const rel of sortedRelations) {
|
|
59
|
+
const source = find(leafsFirst, anscestorOf(rel.source));
|
|
60
|
+
if (!source) {
|
|
61
|
+
continue;
|
|
62
|
+
}
|
|
63
|
+
const target = find(
|
|
64
|
+
leafsFirst,
|
|
65
|
+
allPass([anscestorOf(rel.target), (e) => !isSameHierarchy(e, source)])
|
|
66
|
+
);
|
|
67
|
+
if (!target) {
|
|
68
|
+
continue;
|
|
69
|
+
}
|
|
70
|
+
elementsWithRelations.add(source);
|
|
71
|
+
elementsWithRelations.add(target);
|
|
72
|
+
edgeBuilder.add(source.id, target.id, rel);
|
|
73
|
+
}
|
|
74
|
+
const nodesMap = reduceToMap(/* @__PURE__ */ new Set([...ctx.elements, ...elementsWithRelations]));
|
|
75
|
+
const edges = edgeBuilder.build().map((edge) => {
|
|
76
|
+
while (edge.parent) {
|
|
77
|
+
if (nodesMap.has(edge.parent)) {
|
|
78
|
+
break;
|
|
79
|
+
}
|
|
80
|
+
edge.parent = parentFqn(edge.parent);
|
|
81
|
+
}
|
|
82
|
+
nonNullable(nodesMap.get(edge.source)).outEdges.push(edge.id);
|
|
83
|
+
nonNullable(nodesMap.get(edge.target)).inEdges.push(edge.id);
|
|
84
|
+
return edge;
|
|
85
|
+
});
|
|
86
|
+
const nodes = applyViewRuleStyles(
|
|
87
|
+
view.rules.filter(isViewRuleStyle),
|
|
88
|
+
sortNodes(keepOriginalSortFromView(nodesMap, ctx), edges)
|
|
89
|
+
// map(e => nodesMap.get(e.id)!, Array.from(elements))
|
|
90
|
+
);
|
|
91
|
+
const autoLayoutRule = view.rules.find(isViewRuleAutoLayout);
|
|
92
|
+
return {
|
|
93
|
+
...view,
|
|
94
|
+
autoLayout: autoLayoutRule?.autoLayout ?? "TB",
|
|
95
|
+
nodes,
|
|
96
|
+
edges
|
|
97
|
+
};
|
|
98
|
+
}
|
|
@@ -0,0 +1,324 @@
|
|
|
1
|
+
import { anyPass, both, either, isNil, uniq } from "rambdax";
|
|
2
|
+
import { Expr } from "../types/index.js";
|
|
3
|
+
import { Relations, commonAncestor, isAncestor, isSameHierarchy } from "../utils/index.js";
|
|
4
|
+
import { ComputeCtx } from "./compute-ctx.js";
|
|
5
|
+
const { isAnyInOut, isBetween, isIncoming, isInside, isOutgoing, isAnyBetween } = Relations;
|
|
6
|
+
export const includeElementRef = (ctx, expr) => {
|
|
7
|
+
const elements = expr.isDescedants ? ctx.index.children(expr.element) : [ctx.index.find(expr.element)];
|
|
8
|
+
const filters = [];
|
|
9
|
+
if (expr.isDescedants) {
|
|
10
|
+
elements.forEach((child) => {
|
|
11
|
+
filters.push(both(isInside(expr.element), isAnyInOut(child.id)));
|
|
12
|
+
});
|
|
13
|
+
}
|
|
14
|
+
const ctxElements = uniq([...ctx.elements, ...ctx.implicits]);
|
|
15
|
+
const excludeImplicits = [];
|
|
16
|
+
for (const el of elements) {
|
|
17
|
+
if (ctx.root && ctx.root !== el.id && !isAncestor(el.id, ctx.root)) {
|
|
18
|
+
excludeImplicits.push(...[...ctx.implicits].filter((impl) => isAncestor(el.id, impl.id)));
|
|
19
|
+
}
|
|
20
|
+
for (const ctxEl of ctxElements) {
|
|
21
|
+
if (!isSameHierarchy(el, ctxEl)) {
|
|
22
|
+
filters.push(isAnyBetween(el.id, ctxEl.id));
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
const relations = filters.length ? ctx.index.filterRelations(anyPass(filters)) : [];
|
|
27
|
+
if (excludeImplicits.length == 0) {
|
|
28
|
+
return ctx.include({ elements, relations });
|
|
29
|
+
}
|
|
30
|
+
return ctx.include({ elements, relations }).exclude({ implicits: excludeImplicits });
|
|
31
|
+
};
|
|
32
|
+
export const excludeElementRef = (ctx, expr) => {
|
|
33
|
+
const elements = expr.isDescedants ? ctx.index.children(expr.element) : [ctx.index.find(expr.element)];
|
|
34
|
+
const elementsIds = elements.map((e) => e.id);
|
|
35
|
+
const relations = [...ctx.relations].filter(
|
|
36
|
+
(r) => elementsIds.includes(r.source) || elementsIds.includes(r.target)
|
|
37
|
+
);
|
|
38
|
+
return ctx.exclude({ elements, relations });
|
|
39
|
+
};
|
|
40
|
+
const asElementPredicate = (expr) => {
|
|
41
|
+
if (expr.isEqual) {
|
|
42
|
+
if (Expr.isElementKindExpr(expr)) {
|
|
43
|
+
return (e) => e.kind === expr.elementKind;
|
|
44
|
+
} else {
|
|
45
|
+
return ({ tags }) => !!tags && tags.includes(expr.elementTag);
|
|
46
|
+
}
|
|
47
|
+
} else {
|
|
48
|
+
if (Expr.isElementKindExpr(expr)) {
|
|
49
|
+
return (e) => e.kind !== expr.elementKind;
|
|
50
|
+
} else {
|
|
51
|
+
return ({ tags }) => isNil(tags) || tags.length === 0 || !tags.includes(expr.elementTag);
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
};
|
|
55
|
+
export const includeElementKindOrTag = (ctx, expr) => {
|
|
56
|
+
const elements = ctx.index.elements.filter(asElementPredicate(expr));
|
|
57
|
+
return elements.reduce(
|
|
58
|
+
(accCtx, el) => includeElementRef(accCtx, {
|
|
59
|
+
element: el.id,
|
|
60
|
+
isDescedants: false
|
|
61
|
+
}),
|
|
62
|
+
ctx
|
|
63
|
+
);
|
|
64
|
+
};
|
|
65
|
+
export const excludeElementKindOrTag = (ctx, expr) => {
|
|
66
|
+
const predicate = asElementPredicate(expr);
|
|
67
|
+
const elements = [...ctx.elements].filter(predicate);
|
|
68
|
+
const implicits = [...ctx.implicits].filter(predicate);
|
|
69
|
+
return ctx.exclude({ elements, implicits });
|
|
70
|
+
};
|
|
71
|
+
export const includeWildcardRef = (ctx, _expr) => {
|
|
72
|
+
const { root } = ctx;
|
|
73
|
+
if (root) {
|
|
74
|
+
const elements = [ctx.index.find(root), ...ctx.index.children(root)];
|
|
75
|
+
const allImplicits = [
|
|
76
|
+
...ctx.index.siblings(root),
|
|
77
|
+
...ctx.index.ancestors(root).flatMap((a) => [...ctx.index.siblings(a.id)])
|
|
78
|
+
];
|
|
79
|
+
const inOut = ctx.index.filterRelations(isAnyInOut(root));
|
|
80
|
+
const implicits = [];
|
|
81
|
+
for (const implicit of allImplicits) {
|
|
82
|
+
if (inOut.some(isAnyInOut(implicit.id))) {
|
|
83
|
+
implicits.push(implicit);
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
return ctx.include({
|
|
87
|
+
elements,
|
|
88
|
+
relations: [...ctx.index.filterRelations(isInside(root)), ...inOut],
|
|
89
|
+
implicits
|
|
90
|
+
});
|
|
91
|
+
} else {
|
|
92
|
+
const elements = ctx.index.rootElements();
|
|
93
|
+
if (elements.length <= 1) {
|
|
94
|
+
return new ComputeCtx(ctx.index, ctx.root, new Set(elements));
|
|
95
|
+
}
|
|
96
|
+
const relations = ctx.index.filterRelations(
|
|
97
|
+
(rel) => isNil(commonAncestor(rel.source, rel.target))
|
|
98
|
+
);
|
|
99
|
+
return ctx.include({
|
|
100
|
+
elements,
|
|
101
|
+
relations
|
|
102
|
+
});
|
|
103
|
+
}
|
|
104
|
+
};
|
|
105
|
+
export const excludeWildcardRef = (ctx, _expr) => {
|
|
106
|
+
const { root } = ctx;
|
|
107
|
+
if (root) {
|
|
108
|
+
const relations = [...ctx.relations].filter(either(isInside(root), isAnyInOut(root)));
|
|
109
|
+
return ctx.exclude({
|
|
110
|
+
elements: [...ctx.elements].filter((e) => e.id === root || isAncestor(root, e.id)),
|
|
111
|
+
relations,
|
|
112
|
+
implicits: [...ctx.implicits].filter((e) => relations.some(isAnyInOut(e.id)))
|
|
113
|
+
});
|
|
114
|
+
} else {
|
|
115
|
+
return new ComputeCtx(ctx.index, ctx.root);
|
|
116
|
+
}
|
|
117
|
+
};
|
|
118
|
+
const resolveElements = (ctx, expr) => {
|
|
119
|
+
if (Expr.isWildcard(expr)) {
|
|
120
|
+
if (ctx.root) {
|
|
121
|
+
return [ctx.index.find(ctx.root)];
|
|
122
|
+
} else {
|
|
123
|
+
return ctx.index.rootElements();
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
if (Expr.isElementKindExpr(expr)) {
|
|
127
|
+
return ctx.index.elements.filter((el) => {
|
|
128
|
+
if (expr.isEqual) {
|
|
129
|
+
return el.kind === expr.elementKind;
|
|
130
|
+
}
|
|
131
|
+
return el.kind !== expr.elementKind;
|
|
132
|
+
});
|
|
133
|
+
}
|
|
134
|
+
if (Expr.isElementTagExpr(expr)) {
|
|
135
|
+
return ctx.index.elements.filter((el) => {
|
|
136
|
+
const tags = el.tags;
|
|
137
|
+
if (expr.isEqual) {
|
|
138
|
+
return !!tags && tags.includes(expr.elementTag);
|
|
139
|
+
}
|
|
140
|
+
return isNil(tags) || tags.length === 0 || !tags.includes(expr.elementTag);
|
|
141
|
+
});
|
|
142
|
+
}
|
|
143
|
+
if (expr.isDescedants) {
|
|
144
|
+
return ctx.index.children(expr.element);
|
|
145
|
+
} else {
|
|
146
|
+
return [ctx.index.find(expr.element)];
|
|
147
|
+
}
|
|
148
|
+
};
|
|
149
|
+
export const includeIncomingExpr = (ctx, expr) => {
|
|
150
|
+
if (Expr.isWildcard(expr.incoming) && !ctx.root) {
|
|
151
|
+
return ctx;
|
|
152
|
+
}
|
|
153
|
+
const elements = resolveElements(ctx, expr.incoming);
|
|
154
|
+
if (elements.length === 0) {
|
|
155
|
+
return ctx;
|
|
156
|
+
}
|
|
157
|
+
let allrelations = ctx.index.relations;
|
|
158
|
+
if (Expr.isElementRef(expr.incoming)) {
|
|
159
|
+
allrelations = allrelations.filter(isIncoming(expr.incoming.element));
|
|
160
|
+
}
|
|
161
|
+
const implicits = [];
|
|
162
|
+
const relations = [];
|
|
163
|
+
for (const el of elements) {
|
|
164
|
+
const elRelations = allrelations.filter(isIncoming(el.id));
|
|
165
|
+
if (elRelations.length > 0) {
|
|
166
|
+
relations.push(...elRelations);
|
|
167
|
+
implicits.push(el);
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
return ctx.include({
|
|
171
|
+
relations,
|
|
172
|
+
implicits
|
|
173
|
+
});
|
|
174
|
+
};
|
|
175
|
+
export const excludeIncomingExpr = (ctx, expr) => {
|
|
176
|
+
if (Expr.isWildcard(expr.incoming) && !ctx.root) {
|
|
177
|
+
return ctx;
|
|
178
|
+
}
|
|
179
|
+
const elements = resolveElements(ctx, expr.incoming);
|
|
180
|
+
if (elements.length === 0) {
|
|
181
|
+
return ctx;
|
|
182
|
+
}
|
|
183
|
+
const isIncomings = anyPass(elements.map((el) => isIncoming(el.id)));
|
|
184
|
+
const excluded = [...ctx.relations].filter(isIncomings);
|
|
185
|
+
if (excluded.length > 0) {
|
|
186
|
+
return ctx.exclude({
|
|
187
|
+
relations: excluded
|
|
188
|
+
});
|
|
189
|
+
}
|
|
190
|
+
return ctx;
|
|
191
|
+
};
|
|
192
|
+
export const includeOutgoingExpr = (ctx, expr) => {
|
|
193
|
+
if (Expr.isWildcard(expr.outgoing) && !ctx.root) {
|
|
194
|
+
return ctx;
|
|
195
|
+
}
|
|
196
|
+
const elements = resolveElements(ctx, expr.outgoing);
|
|
197
|
+
if (elements.length === 0) {
|
|
198
|
+
return ctx;
|
|
199
|
+
}
|
|
200
|
+
let allrelations = ctx.index.relations;
|
|
201
|
+
if (Expr.isElementRef(expr.outgoing)) {
|
|
202
|
+
allrelations = allrelations.filter(isOutgoing(expr.outgoing.element));
|
|
203
|
+
}
|
|
204
|
+
const implicits = [];
|
|
205
|
+
const relations = [];
|
|
206
|
+
for (const el of elements) {
|
|
207
|
+
const elRelations = allrelations.filter(isOutgoing(el.id));
|
|
208
|
+
if (elRelations.length > 0) {
|
|
209
|
+
relations.push(...elRelations);
|
|
210
|
+
implicits.push(el);
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
return ctx.include({
|
|
214
|
+
relations,
|
|
215
|
+
implicits
|
|
216
|
+
});
|
|
217
|
+
};
|
|
218
|
+
export const excludeOutgoingExpr = (ctx, expr) => {
|
|
219
|
+
if (Expr.isWildcard(expr.outgoing) && !ctx.root) {
|
|
220
|
+
return ctx;
|
|
221
|
+
}
|
|
222
|
+
const elements = resolveElements(ctx, expr.outgoing);
|
|
223
|
+
if (elements.length === 0) {
|
|
224
|
+
return ctx;
|
|
225
|
+
}
|
|
226
|
+
const isOutgoings = anyPass(elements.map((el) => isOutgoing(el.id)));
|
|
227
|
+
const excluded = [...ctx.relations].filter(isOutgoings);
|
|
228
|
+
if (excluded.length > 0) {
|
|
229
|
+
return ctx.exclude({
|
|
230
|
+
relations: excluded
|
|
231
|
+
});
|
|
232
|
+
}
|
|
233
|
+
return ctx;
|
|
234
|
+
};
|
|
235
|
+
export const includeInOutExpr = (ctx, expr) => {
|
|
236
|
+
if (Expr.isWildcard(expr.inout) && !ctx.root) {
|
|
237
|
+
return ctx;
|
|
238
|
+
}
|
|
239
|
+
const targets = resolveElements(ctx, expr.inout);
|
|
240
|
+
if (targets.length === 0) {
|
|
241
|
+
return ctx;
|
|
242
|
+
}
|
|
243
|
+
let allrelations = ctx.index.relations;
|
|
244
|
+
if (Expr.isElementRef(expr.inout)) {
|
|
245
|
+
allrelations = allrelations.filter(isAnyInOut(expr.inout.element));
|
|
246
|
+
}
|
|
247
|
+
const implicits = [];
|
|
248
|
+
const relations = [];
|
|
249
|
+
for (const target of targets) {
|
|
250
|
+
const foundRelations = allrelations.filter(isAnyInOut(target.id));
|
|
251
|
+
if (foundRelations.length > 0) {
|
|
252
|
+
relations.push(...foundRelations);
|
|
253
|
+
implicits.push(target);
|
|
254
|
+
}
|
|
255
|
+
}
|
|
256
|
+
return ctx.include({
|
|
257
|
+
relations,
|
|
258
|
+
implicits
|
|
259
|
+
});
|
|
260
|
+
};
|
|
261
|
+
export const excludeInOutExpr = (ctx, expr) => {
|
|
262
|
+
if (Expr.isWildcard(expr.inout) && !ctx.root) {
|
|
263
|
+
return ctx;
|
|
264
|
+
}
|
|
265
|
+
const targets = resolveElements(ctx, expr.inout);
|
|
266
|
+
if (targets.length === 0) {
|
|
267
|
+
return ctx;
|
|
268
|
+
}
|
|
269
|
+
const excluded = [...ctx.relations].filter(anyPass(targets.map((t) => isAnyInOut(t.id))));
|
|
270
|
+
if (excluded.length > 0) {
|
|
271
|
+
return ctx.exclude({
|
|
272
|
+
relations: excluded
|
|
273
|
+
});
|
|
274
|
+
}
|
|
275
|
+
return ctx;
|
|
276
|
+
};
|
|
277
|
+
export const includeRelationExpr = (ctx, expr) => {
|
|
278
|
+
const sources = resolveElements(ctx, expr.source);
|
|
279
|
+
const targets = resolveElements(ctx, expr.target);
|
|
280
|
+
if (sources.length === 0 || targets.length === 0) {
|
|
281
|
+
return ctx;
|
|
282
|
+
}
|
|
283
|
+
const implicits = [];
|
|
284
|
+
const relations = [];
|
|
285
|
+
for (const source of sources) {
|
|
286
|
+
for (const target of targets) {
|
|
287
|
+
if (isSameHierarchy(source, target)) {
|
|
288
|
+
continue;
|
|
289
|
+
}
|
|
290
|
+
const foundRelations = ctx.index.filterRelations(isBetween(source.id, target.id));
|
|
291
|
+
if (foundRelations.length > 0) {
|
|
292
|
+
relations.push(...foundRelations);
|
|
293
|
+
implicits.push(source, target);
|
|
294
|
+
}
|
|
295
|
+
}
|
|
296
|
+
}
|
|
297
|
+
return ctx.include({
|
|
298
|
+
relations,
|
|
299
|
+
implicits
|
|
300
|
+
});
|
|
301
|
+
};
|
|
302
|
+
export const excludeRelationExpr = (ctx, expr) => {
|
|
303
|
+
const sources = resolveElements(ctx, expr.source);
|
|
304
|
+
const targets = resolveElements(ctx, expr.target);
|
|
305
|
+
const filters = [];
|
|
306
|
+
for (const source of sources) {
|
|
307
|
+
for (const target of targets) {
|
|
308
|
+
if (isSameHierarchy(source, target)) {
|
|
309
|
+
continue;
|
|
310
|
+
}
|
|
311
|
+
filters.push(isBetween(source.id, target.id));
|
|
312
|
+
}
|
|
313
|
+
}
|
|
314
|
+
if (filters.length == 0) {
|
|
315
|
+
return ctx;
|
|
316
|
+
}
|
|
317
|
+
const excluded = [...ctx.relations].filter(anyPass(filters));
|
|
318
|
+
if (excluded.length == 0) {
|
|
319
|
+
return ctx;
|
|
320
|
+
}
|
|
321
|
+
return ctx.exclude({
|
|
322
|
+
relations: excluded
|
|
323
|
+
});
|
|
324
|
+
};
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { find } from "rambdax";
|
|
2
|
+
import { normalizeError } from "../errors/index.js";
|
|
3
|
+
import { computeElementView } from "./compute-element-view.js";
|
|
4
|
+
export function computeView(view, index) {
|
|
5
|
+
try {
|
|
6
|
+
return {
|
|
7
|
+
isSuccess: true,
|
|
8
|
+
view: computeElementView(view, index)
|
|
9
|
+
};
|
|
10
|
+
} catch (e) {
|
|
11
|
+
return {
|
|
12
|
+
isSuccess: false,
|
|
13
|
+
error: normalizeError(e),
|
|
14
|
+
view: void 0
|
|
15
|
+
};
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
export function assignNavigateTo(views) {
|
|
19
|
+
const allElementViews = /* @__PURE__ */ new Map();
|
|
20
|
+
for (const v of views) {
|
|
21
|
+
if (v.viewOf && !v.extends) {
|
|
22
|
+
const viewsOf = allElementViews.get(v.viewOf) ?? [];
|
|
23
|
+
viewsOf.push(v.id);
|
|
24
|
+
allElementViews.set(v.viewOf, viewsOf);
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
for (const { id, nodes } of views) {
|
|
28
|
+
for (const node of nodes) {
|
|
29
|
+
const navigateTo = find((v) => v !== id, allElementViews.get(node.id) ?? []);
|
|
30
|
+
if (navigateTo) {
|
|
31
|
+
node.navigateTo = navigateTo;
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
return views;
|
|
36
|
+
}
|