@likec4/core 0.6.1 → 0.6.2
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/package.json +3 -3
- package/dist/__test__/data.d.ts +0 -173
- package/dist/__test__/data.js +0 -188
- package/dist/__test__/index.d.ts +0 -1
- package/dist/__test__/index.js +0 -1
- package/dist/compute-view/EdgeBuilder.d.ts +0 -7
- package/dist/compute-view/EdgeBuilder.js +0 -34
- package/dist/compute-view/compute-view.d.ts +0 -11
- package/dist/compute-view/compute-view.js +0 -14
- package/dist/compute-view/compute.element-view.d.ts +0 -4
- package/dist/compute-view/compute.element-view.js +0 -168
- package/dist/compute-view/compute.element-view.spec.d.ts +0 -1
- package/dist/compute-view/compute.element-view.spec.js +0 -175
- package/dist/compute-view/index.d.ts +0 -2
- package/dist/compute-view/index.js +0 -1
- package/dist/compute-view/utils/anyPossibleRelations.d.ts +0 -2
- package/dist/compute-view/utils/anyPossibleRelations.js +0 -12
- package/dist/compute-view/utils/evaluate-expression.d.ts +0 -10
- package/dist/compute-view/utils/evaluate-expression.js +0 -186
- package/dist/compute-view/utils/sortNodes.d.ts +0 -2
- package/dist/compute-view/utils/sortNodes.js +0 -42
- package/dist/compute-view/utils/sortNodes.spec.d.ts +0 -1
- package/dist/compute-view/utils/sortNodes.spec.js +0 -267
- package/dist/index.d.ts +0 -4
- package/dist/index.js +0 -3
- package/dist/model-index/index.d.ts +0 -1
- package/dist/model-index/index.js +0 -1
- package/dist/model-index/model-index.d.ts +0 -30
- package/dist/model-index/model-index.js +0 -143
- package/dist/types/computed-view.d.ts +0 -30
- package/dist/types/computed-view.js +0 -1
- package/dist/types/diagram.d.ts +0 -27
- package/dist/types/diagram.js +0 -1
- package/dist/types/element.d.ts +0 -26
- package/dist/types/element.js +0 -5
- package/dist/types/expression.d.ts +0 -43
- package/dist/types/expression.js +0 -24
- package/dist/types/index.d.ts +0 -10
- package/dist/types/index.js +0 -2
- package/dist/types/model.d.ts +0 -9
- package/dist/types/model.js +0 -1
- package/dist/types/opaque.d.ts +0 -102
- package/dist/types/opaque.js +0 -1
- package/dist/types/relation.d.ts +0 -10
- package/dist/types/relation.js +0 -1
- package/dist/types/view.d.ts +0 -29
- package/dist/types/view.js +0 -9
- package/dist/utils/fqn.d.ts +0 -10
- package/dist/utils/fqn.js +0 -51
- package/dist/utils/fqn.spec.d.ts +0 -1
- package/dist/utils/fqn.spec.js +0 -47
- package/dist/utils/guards.d.ts +0 -3
- package/dist/utils/guards.js +0 -10
- package/dist/utils/index.d.ts +0 -3
- package/dist/utils/index.js +0 -3
- package/dist/utils/relations.d.ts +0 -16
- package/dist/utils/relations.js +0 -36
|
@@ -1,175 +0,0 @@
|
|
|
1
|
-
import { expect, test } from 'vitest';
|
|
2
|
-
import { fakeModel } from '../__test__';
|
|
3
|
-
import { computeElementView } from './compute.element-view';
|
|
4
|
-
test('index view', () => {
|
|
5
|
-
const { nodes, edges } = computeElementView({
|
|
6
|
-
id: 'index',
|
|
7
|
-
title: '',
|
|
8
|
-
rules: [
|
|
9
|
-
{
|
|
10
|
-
isInclude: true,
|
|
11
|
-
exprs: [
|
|
12
|
-
{
|
|
13
|
-
wildcard: true
|
|
14
|
-
}
|
|
15
|
-
]
|
|
16
|
-
}
|
|
17
|
-
]
|
|
18
|
-
}, fakeModel());
|
|
19
|
-
expect(nodes.map(n => n.id)).toEqual(['support', 'customer', 'cloud', 'amazon']);
|
|
20
|
-
expect(edges.map(e => e.id)).toEqual(['support:cloud', 'customer:cloud', 'cloud:amazon']);
|
|
21
|
-
});
|
|
22
|
-
test('view of cloud', () => {
|
|
23
|
-
const view = computeElementView({
|
|
24
|
-
id: 'cloud',
|
|
25
|
-
title: '',
|
|
26
|
-
viewOf: 'cloud',
|
|
27
|
-
rules: [
|
|
28
|
-
{
|
|
29
|
-
isInclude: true,
|
|
30
|
-
exprs: [
|
|
31
|
-
{
|
|
32
|
-
wildcard: true
|
|
33
|
-
}
|
|
34
|
-
]
|
|
35
|
-
}
|
|
36
|
-
]
|
|
37
|
-
}, fakeModel());
|
|
38
|
-
const { nodes, edges } = view;
|
|
39
|
-
expect(nodes.map(n => n.id)).toEqual([
|
|
40
|
-
'support',
|
|
41
|
-
'customer',
|
|
42
|
-
'cloud',
|
|
43
|
-
'cloud.frontend',
|
|
44
|
-
'cloud.backend',
|
|
45
|
-
'amazon'
|
|
46
|
-
]);
|
|
47
|
-
expect(edges.map(e => e.id)).toEqual([
|
|
48
|
-
'cloud.frontend:cloud.backend',
|
|
49
|
-
'cloud.backend:amazon',
|
|
50
|
-
'support:cloud.frontend',
|
|
51
|
-
'customer:cloud.frontend'
|
|
52
|
-
]);
|
|
53
|
-
expect(view).toMatchSnapshot();
|
|
54
|
-
});
|
|
55
|
-
test('view with 3 levels', () => {
|
|
56
|
-
const view = computeElementView({
|
|
57
|
-
id: 'cloud3levels',
|
|
58
|
-
title: '',
|
|
59
|
-
viewOf: 'cloud',
|
|
60
|
-
rules: [
|
|
61
|
-
{
|
|
62
|
-
isInclude: true,
|
|
63
|
-
exprs: [
|
|
64
|
-
// include *
|
|
65
|
-
{ wildcard: true },
|
|
66
|
-
// include cloud.frontend.*
|
|
67
|
-
{ element: 'cloud.frontend', isDescedants: true },
|
|
68
|
-
// include cloud.backend.*
|
|
69
|
-
{ element: 'cloud.backend', isDescedants: true }
|
|
70
|
-
]
|
|
71
|
-
},
|
|
72
|
-
{
|
|
73
|
-
isInclude: false,
|
|
74
|
-
exprs: [
|
|
75
|
-
// exclude cloud.frontend
|
|
76
|
-
{ element: 'cloud.frontend', isDescedants: false }
|
|
77
|
-
]
|
|
78
|
-
}
|
|
79
|
-
]
|
|
80
|
-
}, fakeModel());
|
|
81
|
-
expect(view.nodes.map(n => n.id)).toEqual([
|
|
82
|
-
'support',
|
|
83
|
-
'customer',
|
|
84
|
-
'cloud',
|
|
85
|
-
'cloud.frontend.dashboard',
|
|
86
|
-
'cloud.frontend.adminPanel',
|
|
87
|
-
'cloud.backend',
|
|
88
|
-
'cloud.backend.graphql',
|
|
89
|
-
'cloud.backend.storage',
|
|
90
|
-
'amazon'
|
|
91
|
-
]);
|
|
92
|
-
expect(view).toMatchSnapshot();
|
|
93
|
-
});
|
|
94
|
-
test('view of amazon', () => {
|
|
95
|
-
const { nodes, edges } = computeElementView({
|
|
96
|
-
id: 'amazon',
|
|
97
|
-
title: '',
|
|
98
|
-
viewOf: 'amazon',
|
|
99
|
-
rules: [
|
|
100
|
-
{
|
|
101
|
-
isInclude: true,
|
|
102
|
-
exprs: [
|
|
103
|
-
// include *
|
|
104
|
-
{ wildcard: true },
|
|
105
|
-
// include cloud
|
|
106
|
-
{ element: 'cloud', isDescedants: false },
|
|
107
|
-
// include cloud.* -> amazon
|
|
108
|
-
{
|
|
109
|
-
source: { element: 'cloud', isDescedants: true },
|
|
110
|
-
target: { element: 'amazon', isDescedants: false }
|
|
111
|
-
}
|
|
112
|
-
]
|
|
113
|
-
}
|
|
114
|
-
]
|
|
115
|
-
}, fakeModel());
|
|
116
|
-
expect(nodes.map(n => n.id)).toEqual(['cloud', 'cloud.backend', 'amazon', 'amazon.s3']);
|
|
117
|
-
expect(edges.map(e => e.id)).toEqual(['cloud.backend:amazon.s3']);
|
|
118
|
-
});
|
|
119
|
-
test('index view with applied styles', () => {
|
|
120
|
-
const { nodes } = computeElementView({
|
|
121
|
-
id: 'index',
|
|
122
|
-
rules: [
|
|
123
|
-
{
|
|
124
|
-
isInclude: true,
|
|
125
|
-
exprs: [{ wildcard: true }, { element: 'cloud.backend', isDescedants: false }]
|
|
126
|
-
},
|
|
127
|
-
// all elements
|
|
128
|
-
// color: secondary
|
|
129
|
-
{
|
|
130
|
-
targets: [{ wildcard: true }],
|
|
131
|
-
style: {
|
|
132
|
-
color: 'secondary',
|
|
133
|
-
shape: 'storage'
|
|
134
|
-
}
|
|
135
|
-
},
|
|
136
|
-
// cloud
|
|
137
|
-
// color: muted
|
|
138
|
-
{
|
|
139
|
-
targets: [{ element: 'cloud', isDescedants: false }],
|
|
140
|
-
style: {
|
|
141
|
-
color: 'muted'
|
|
142
|
-
}
|
|
143
|
-
},
|
|
144
|
-
// cloud.*
|
|
145
|
-
// shape: browser
|
|
146
|
-
{
|
|
147
|
-
targets: [{ element: 'cloud', isDescedants: true }],
|
|
148
|
-
style: {
|
|
149
|
-
shape: 'browser'
|
|
150
|
-
}
|
|
151
|
-
}
|
|
152
|
-
]
|
|
153
|
-
}, fakeModel());
|
|
154
|
-
const amazon = nodes.find(n => n.id === 'amazon');
|
|
155
|
-
const customer = nodes.find(n => n.id === 'customer');
|
|
156
|
-
const cloud = nodes.find(n => n.id === 'cloud');
|
|
157
|
-
const backend = nodes.find(n => n.id === 'cloud.backend');
|
|
158
|
-
expect(amazon).toMatchObject({
|
|
159
|
-
color: 'secondary',
|
|
160
|
-
shape: 'storage'
|
|
161
|
-
});
|
|
162
|
-
expect(customer).toMatchObject({
|
|
163
|
-
color: 'secondary',
|
|
164
|
-
shape: 'storage'
|
|
165
|
-
});
|
|
166
|
-
expect(cloud).toMatchObject({
|
|
167
|
-
color: 'muted',
|
|
168
|
-
shape: 'storage'
|
|
169
|
-
});
|
|
170
|
-
expect(backend).toMatchObject({
|
|
171
|
-
parent: 'cloud',
|
|
172
|
-
color: 'secondary',
|
|
173
|
-
shape: 'browser'
|
|
174
|
-
});
|
|
175
|
-
});
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export { computeView, computeViews } from './compute-view';
|
|
@@ -1,12 +0,0 @@
|
|
|
1
|
-
import { prop, uniqBy } from 'rambdax';
|
|
2
|
-
import { compareByFqnHierarchically, isAncestor } from '../../utils/fqn';
|
|
3
|
-
export function* anyPossibleRelations(elements) {
|
|
4
|
-
const uniqElements = uniqBy(prop('id'), elements).sort(compareByFqnHierarchically).reverse();
|
|
5
|
-
for (const source of uniqElements) {
|
|
6
|
-
for (const target of uniqElements) {
|
|
7
|
-
if (source !== target && !isAncestor(source, target) && !isAncestor(target, source)) {
|
|
8
|
-
yield [source, target];
|
|
9
|
-
}
|
|
10
|
-
}
|
|
11
|
-
}
|
|
12
|
-
}
|
|
@@ -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 {};
|
|
@@ -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
|
-
}
|
|
@@ -1,42 +0,0 @@
|
|
|
1
|
-
import { Graph, alg } from '@dagrejs/graphlib';
|
|
2
|
-
export function sortNodes(_nodes, edges) {
|
|
3
|
-
const g = new Graph({
|
|
4
|
-
compound: true,
|
|
5
|
-
directed: true,
|
|
6
|
-
multigraph: false
|
|
7
|
-
});
|
|
8
|
-
for (const nd of _nodes.values()) {
|
|
9
|
-
g.setNode(nd.id);
|
|
10
|
-
// console.log(`add ${nd.id}`)
|
|
11
|
-
if (nd.parent) {
|
|
12
|
-
g.setEdge(nd.parent, nd.id);
|
|
13
|
-
// console.log(`${nd.parent} -> ${nd.id}`)
|
|
14
|
-
}
|
|
15
|
-
}
|
|
16
|
-
for (const edge of edges) {
|
|
17
|
-
const source = _nodes.get(edge.source);
|
|
18
|
-
let target = _nodes.get(edge.target);
|
|
19
|
-
while (source && target) {
|
|
20
|
-
if (!g.hasEdge(source.id, target.id)) {
|
|
21
|
-
g.setEdge(source.id, target.id);
|
|
22
|
-
// console.log(`${source.id} -> ${target.id}`)
|
|
23
|
-
if (!alg.isAcyclic(g)) {
|
|
24
|
-
g.removeEdge(source.id, target.id);
|
|
25
|
-
// console.log(`remove ${source.id} -> ${target.id}`)
|
|
26
|
-
}
|
|
27
|
-
}
|
|
28
|
-
if (target.parent && target.parent !== edge.parent) {
|
|
29
|
-
target = _nodes.get(target.parent);
|
|
30
|
-
}
|
|
31
|
-
else {
|
|
32
|
-
target = undefined;
|
|
33
|
-
}
|
|
34
|
-
}
|
|
35
|
-
}
|
|
36
|
-
const sorted = alg.topsort(g);
|
|
37
|
-
const nodes = sorted.map(id => _nodes.get(id));
|
|
38
|
-
for (const node of nodes) {
|
|
39
|
-
node.children = nodes.flatMap(n => (n.parent === node.id ? n.id : []));
|
|
40
|
-
}
|
|
41
|
-
return nodes;
|
|
42
|
-
}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export {};
|