@likec4/core 0.6.2 → 0.7.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/__test__/data.d.ts +174 -0
- package/dist/__test__/data.js +188 -0
- package/dist/__test__/index.d.ts +2 -0
- package/dist/__test__/index.js +1 -0
- package/dist/compute-view/EdgeBuilder.d.ts +8 -0
- package/dist/compute-view/EdgeBuilder.js +34 -0
- package/dist/compute-view/compute.d.ts +12 -0
- package/dist/compute-view/compute.element-view.d.ts +5 -0
- package/dist/compute-view/compute.element-view.js +168 -0
- package/dist/compute-view/compute.js +14 -0
- package/dist/compute-view/index.d.ts +3 -0
- package/dist/compute-view/index.js +1 -0
- package/dist/compute-view/utils/anyPossibleRelations.d.ts +3 -0
- package/dist/compute-view/utils/anyPossibleRelations.js +12 -0
- package/dist/compute-view/utils/evaluate-expression.d.ts +11 -0
- package/dist/compute-view/utils/evaluate-expression.js +186 -0
- package/dist/compute-view/utils/sortNodes.d.ts +3 -0
- package/dist/compute-view/utils/sortNodes.js +42 -0
- package/dist/index.d.ts +5 -0
- package/dist/index.js +3 -0
- package/dist/model-index/ModelIndex.d.ts +31 -0
- package/dist/model-index/ModelIndex.js +143 -0
- package/dist/model-index/index.d.ts +2 -0
- package/dist/model-index/index.js +1 -0
- package/dist/types/computed-view.d.ts +31 -0
- package/dist/types/computed-view.js +1 -0
- package/dist/types/diagram.d.ts +28 -0
- package/dist/types/diagram.js +1 -0
- package/dist/types/element.d.ts +27 -0
- package/dist/types/element.js +5 -0
- package/dist/types/expression.d.ts +44 -0
- package/dist/types/expression.js +24 -0
- package/dist/types/index.d.ts +11 -0
- package/dist/types/index.js +2 -0
- package/dist/types/model.d.ts +10 -0
- package/dist/types/model.js +1 -0
- package/dist/types/opaque.d.ts +103 -0
- package/dist/types/opaque.js +1 -0
- package/dist/types/relation.d.ts +11 -0
- package/dist/types/relation.js +1 -0
- package/dist/types/view.d.ts +30 -0
- package/dist/types/view.js +9 -0
- package/dist/utils/fqn.d.ts +11 -0
- package/dist/utils/fqn.js +51 -0
- package/dist/utils/guards.d.ts +4 -0
- package/dist/utils/guards.js +10 -0
- package/dist/utils/index.d.ts +4 -0
- package/dist/utils/index.js +3 -0
- package/dist/utils/relations.d.ts +17 -0
- package/dist/utils/relations.js +36 -0
- package/package.json +18 -16
|
@@ -0,0 +1,174 @@
|
|
|
1
|
+
import { ModelIndex } from '../model-index';
|
|
2
|
+
import type { ElementKind, ElementView, Fqn, RelationID } from '../types';
|
|
3
|
+
/**
|
|
4
|
+
┌──────────────────────────────────────────────────┐
|
|
5
|
+
│ cloud │
|
|
6
|
+
│ ┌───────────────────────────────────────────┐ │
|
|
7
|
+
│ │ frontend │ │
|
|
8
|
+
┏━━━━━━━━━━┓ │ │ ┏━━━━━━━━━━━━━┓ ┏━━━━━━━━━━━━━━━━┓ │ │ ┏━━━━━━━━━━━┓
|
|
9
|
+
┃ ┃ │ │ ┃ ┃ ┃ ┃ │ │ ┃ ┃
|
|
10
|
+
┃ customer ┃──┼──┼──▶┃ dashboard ┃ ┃ adminpanel ┃◀───┼───┼───┃ support ┃
|
|
11
|
+
┃ ┃ │ │ ┃ ┃ ┃ ┃ │ │ ┃ ┃
|
|
12
|
+
┗━━━━━━━━━━┛ │ │ ┗━━━━━━┳━━━━━━┛ ┗━━━━━━━━┳━━━━━━━┛ │ │ ┗━━━━━━━━━━━┛
|
|
13
|
+
│ └──────────┼───────────────────┼────────────┘ │
|
|
14
|
+
│ ├───────────────────┘ │
|
|
15
|
+
│ │ │
|
|
16
|
+
│ ┌──────────┼────────────────────────────────┐ │
|
|
17
|
+
│ │ ▼ backend │ │
|
|
18
|
+
│ │ ┏━━━━━━━━━━━━━┓ ┏━━━━━━━━━━━━━┓ │ │
|
|
19
|
+
│ │ ┃ ┃ ┃ ┃ │ │
|
|
20
|
+
│ │ ┃ graphlql ┃──────▶┃ storage ┃ │ │
|
|
21
|
+
│ │ ┃ ┃ ┃ ┃ │ │
|
|
22
|
+
│ │ ┗━━━━━━━━━━━━━┛ ┗━━━━━━┳━━━━━━┛ │ │
|
|
23
|
+
│ └────────────────────────────────┼──────────┘ │
|
|
24
|
+
└───────────────────────────────────┼──────────────┘
|
|
25
|
+
│
|
|
26
|
+
┌─────────┼─────────┐
|
|
27
|
+
│ amazon │ │
|
|
28
|
+
│ ▼ │
|
|
29
|
+
│ ┏━━━━━━━━━━━━━━┓ │
|
|
30
|
+
│ ┃ ┃ │
|
|
31
|
+
│ ┃ s3 ┃ │
|
|
32
|
+
│ ┃ ┃ │
|
|
33
|
+
│ ┗━━━━━━━━━━━━━━┛ │
|
|
34
|
+
└───────────────────┘
|
|
35
|
+
|
|
36
|
+
specification {
|
|
37
|
+
element actor
|
|
38
|
+
element system
|
|
39
|
+
element component
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
model {
|
|
43
|
+
|
|
44
|
+
actor customer
|
|
45
|
+
actor support
|
|
46
|
+
|
|
47
|
+
system cloud {
|
|
48
|
+
component backend {
|
|
49
|
+
component graphql
|
|
50
|
+
component storage
|
|
51
|
+
|
|
52
|
+
graphql -> storage
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
component frontend {
|
|
56
|
+
component dashboard {
|
|
57
|
+
-> graphql
|
|
58
|
+
}
|
|
59
|
+
component adminPanel {
|
|
60
|
+
-> graphql
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
customer -> dashboard
|
|
66
|
+
support -> adminPanel
|
|
67
|
+
|
|
68
|
+
system amazon {
|
|
69
|
+
component s3
|
|
70
|
+
|
|
71
|
+
cloud.backend.storage -> s3
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
*/
|
|
77
|
+
export declare const fakeElements: {
|
|
78
|
+
amazon: {
|
|
79
|
+
id: Fqn;
|
|
80
|
+
kind: ElementKind;
|
|
81
|
+
title: string;
|
|
82
|
+
};
|
|
83
|
+
cloud: {
|
|
84
|
+
id: Fqn;
|
|
85
|
+
kind: ElementKind;
|
|
86
|
+
title: string;
|
|
87
|
+
};
|
|
88
|
+
customer: {
|
|
89
|
+
id: Fqn;
|
|
90
|
+
kind: ElementKind;
|
|
91
|
+
title: string;
|
|
92
|
+
};
|
|
93
|
+
support: {
|
|
94
|
+
id: Fqn;
|
|
95
|
+
kind: ElementKind;
|
|
96
|
+
title: string;
|
|
97
|
+
};
|
|
98
|
+
'amazon.s3': {
|
|
99
|
+
id: Fqn;
|
|
100
|
+
kind: ElementKind;
|
|
101
|
+
title: string;
|
|
102
|
+
};
|
|
103
|
+
'cloud.backend': {
|
|
104
|
+
id: Fqn;
|
|
105
|
+
kind: ElementKind;
|
|
106
|
+
title: string;
|
|
107
|
+
};
|
|
108
|
+
'cloud.frontend': {
|
|
109
|
+
id: Fqn;
|
|
110
|
+
kind: ElementKind;
|
|
111
|
+
title: string;
|
|
112
|
+
};
|
|
113
|
+
'cloud.backend.graphql': {
|
|
114
|
+
id: Fqn;
|
|
115
|
+
kind: ElementKind;
|
|
116
|
+
title: string;
|
|
117
|
+
};
|
|
118
|
+
'cloud.backend.storage': {
|
|
119
|
+
id: Fqn;
|
|
120
|
+
kind: ElementKind;
|
|
121
|
+
title: string;
|
|
122
|
+
};
|
|
123
|
+
'cloud.frontend.adminPanel': {
|
|
124
|
+
id: Fqn;
|
|
125
|
+
kind: ElementKind;
|
|
126
|
+
title: string;
|
|
127
|
+
};
|
|
128
|
+
'cloud.frontend.dashboard': {
|
|
129
|
+
id: Fqn;
|
|
130
|
+
kind: ElementKind;
|
|
131
|
+
title: string;
|
|
132
|
+
};
|
|
133
|
+
};
|
|
134
|
+
export declare const fakeRelations: {
|
|
135
|
+
'customer:cloud.frontend.dashboard': {
|
|
136
|
+
id: RelationID;
|
|
137
|
+
source: Fqn;
|
|
138
|
+
target: Fqn;
|
|
139
|
+
title: string;
|
|
140
|
+
};
|
|
141
|
+
'support:cloud.frontend.adminPanel': {
|
|
142
|
+
id: RelationID;
|
|
143
|
+
source: Fqn;
|
|
144
|
+
target: Fqn;
|
|
145
|
+
title: string;
|
|
146
|
+
};
|
|
147
|
+
'cloud.backend.storage:amazon.s3': {
|
|
148
|
+
id: RelationID;
|
|
149
|
+
source: Fqn;
|
|
150
|
+
target: Fqn;
|
|
151
|
+
title: string;
|
|
152
|
+
};
|
|
153
|
+
'cloud.backend.graphql:cloud.backend.storage': {
|
|
154
|
+
id: RelationID;
|
|
155
|
+
source: Fqn;
|
|
156
|
+
target: Fqn;
|
|
157
|
+
title: string;
|
|
158
|
+
};
|
|
159
|
+
'cloud.frontend.dashboard:cloud.backend.graphql': {
|
|
160
|
+
id: RelationID;
|
|
161
|
+
source: Fqn;
|
|
162
|
+
target: Fqn;
|
|
163
|
+
title: string;
|
|
164
|
+
};
|
|
165
|
+
'cloud.frontend.adminPanel:cloud.backend.graphql': {
|
|
166
|
+
id: RelationID;
|
|
167
|
+
source: Fqn;
|
|
168
|
+
target: Fqn;
|
|
169
|
+
title: string;
|
|
170
|
+
};
|
|
171
|
+
};
|
|
172
|
+
export declare const fakeElementView: ElementView;
|
|
173
|
+
export declare const fakeModel: () => ModelIndex;
|
|
174
|
+
//# sourceMappingURL=data.d.ts.map
|
|
@@ -0,0 +1,188 @@
|
|
|
1
|
+
import { ModelIndex } from '../model-index';
|
|
2
|
+
/**
|
|
3
|
+
┌──────────────────────────────────────────────────┐
|
|
4
|
+
│ cloud │
|
|
5
|
+
│ ┌───────────────────────────────────────────┐ │
|
|
6
|
+
│ │ frontend │ │
|
|
7
|
+
┏━━━━━━━━━━┓ │ │ ┏━━━━━━━━━━━━━┓ ┏━━━━━━━━━━━━━━━━┓ │ │ ┏━━━━━━━━━━━┓
|
|
8
|
+
┃ ┃ │ │ ┃ ┃ ┃ ┃ │ │ ┃ ┃
|
|
9
|
+
┃ customer ┃──┼──┼──▶┃ dashboard ┃ ┃ adminpanel ┃◀───┼───┼───┃ support ┃
|
|
10
|
+
┃ ┃ │ │ ┃ ┃ ┃ ┃ │ │ ┃ ┃
|
|
11
|
+
┗━━━━━━━━━━┛ │ │ ┗━━━━━━┳━━━━━━┛ ┗━━━━━━━━┳━━━━━━━┛ │ │ ┗━━━━━━━━━━━┛
|
|
12
|
+
│ └──────────┼───────────────────┼────────────┘ │
|
|
13
|
+
│ ├───────────────────┘ │
|
|
14
|
+
│ │ │
|
|
15
|
+
│ ┌──────────┼────────────────────────────────┐ │
|
|
16
|
+
│ │ ▼ backend │ │
|
|
17
|
+
│ │ ┏━━━━━━━━━━━━━┓ ┏━━━━━━━━━━━━━┓ │ │
|
|
18
|
+
│ │ ┃ ┃ ┃ ┃ │ │
|
|
19
|
+
│ │ ┃ graphlql ┃──────▶┃ storage ┃ │ │
|
|
20
|
+
│ │ ┃ ┃ ┃ ┃ │ │
|
|
21
|
+
│ │ ┗━━━━━━━━━━━━━┛ ┗━━━━━━┳━━━━━━┛ │ │
|
|
22
|
+
│ └────────────────────────────────┼──────────┘ │
|
|
23
|
+
└───────────────────────────────────┼──────────────┘
|
|
24
|
+
│
|
|
25
|
+
┌─────────┼─────────┐
|
|
26
|
+
│ amazon │ │
|
|
27
|
+
│ ▼ │
|
|
28
|
+
│ ┏━━━━━━━━━━━━━━┓ │
|
|
29
|
+
│ ┃ ┃ │
|
|
30
|
+
│ ┃ s3 ┃ │
|
|
31
|
+
│ ┃ ┃ │
|
|
32
|
+
│ ┗━━━━━━━━━━━━━━┛ │
|
|
33
|
+
└───────────────────┘
|
|
34
|
+
|
|
35
|
+
specification {
|
|
36
|
+
element actor
|
|
37
|
+
element system
|
|
38
|
+
element component
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
model {
|
|
42
|
+
|
|
43
|
+
actor customer
|
|
44
|
+
actor support
|
|
45
|
+
|
|
46
|
+
system cloud {
|
|
47
|
+
component backend {
|
|
48
|
+
component graphql
|
|
49
|
+
component storage
|
|
50
|
+
|
|
51
|
+
graphql -> storage
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
component frontend {
|
|
55
|
+
component dashboard {
|
|
56
|
+
-> graphql
|
|
57
|
+
}
|
|
58
|
+
component adminPanel {
|
|
59
|
+
-> graphql
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
customer -> dashboard
|
|
65
|
+
support -> adminPanel
|
|
66
|
+
|
|
67
|
+
system amazon {
|
|
68
|
+
component s3
|
|
69
|
+
|
|
70
|
+
cloud.backend.storage -> s3
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
*/
|
|
76
|
+
export const fakeElements = {
|
|
77
|
+
amazon: {
|
|
78
|
+
id: 'amazon',
|
|
79
|
+
kind: 'system',
|
|
80
|
+
title: 'amazon'
|
|
81
|
+
},
|
|
82
|
+
cloud: {
|
|
83
|
+
id: 'cloud',
|
|
84
|
+
kind: 'system',
|
|
85
|
+
title: 'cloud'
|
|
86
|
+
},
|
|
87
|
+
customer: {
|
|
88
|
+
id: 'customer',
|
|
89
|
+
kind: 'actor',
|
|
90
|
+
title: 'customer'
|
|
91
|
+
},
|
|
92
|
+
support: {
|
|
93
|
+
id: 'support',
|
|
94
|
+
kind: 'actor',
|
|
95
|
+
title: 'support'
|
|
96
|
+
},
|
|
97
|
+
'amazon.s3': {
|
|
98
|
+
id: 'amazon.s3',
|
|
99
|
+
kind: 'component',
|
|
100
|
+
title: 's3'
|
|
101
|
+
},
|
|
102
|
+
'cloud.backend': {
|
|
103
|
+
id: 'cloud.backend',
|
|
104
|
+
kind: 'component',
|
|
105
|
+
title: 'backend'
|
|
106
|
+
},
|
|
107
|
+
'cloud.frontend': {
|
|
108
|
+
id: 'cloud.frontend',
|
|
109
|
+
kind: 'component',
|
|
110
|
+
title: 'frontend'
|
|
111
|
+
},
|
|
112
|
+
'cloud.backend.graphql': {
|
|
113
|
+
id: 'cloud.backend.graphql',
|
|
114
|
+
kind: 'component',
|
|
115
|
+
title: 'graphql'
|
|
116
|
+
},
|
|
117
|
+
'cloud.backend.storage': {
|
|
118
|
+
id: 'cloud.backend.storage',
|
|
119
|
+
kind: 'component',
|
|
120
|
+
title: 'storage'
|
|
121
|
+
},
|
|
122
|
+
'cloud.frontend.adminPanel': {
|
|
123
|
+
id: 'cloud.frontend.adminPanel',
|
|
124
|
+
kind: 'component',
|
|
125
|
+
title: 'adminPanel'
|
|
126
|
+
},
|
|
127
|
+
'cloud.frontend.dashboard': {
|
|
128
|
+
id: 'cloud.frontend.dashboard',
|
|
129
|
+
kind: 'component',
|
|
130
|
+
title: 'dashboard'
|
|
131
|
+
}
|
|
132
|
+
};
|
|
133
|
+
export const fakeRelations = {
|
|
134
|
+
'customer:cloud.frontend.dashboard': {
|
|
135
|
+
id: 'customer:cloud.frontend.dashboard',
|
|
136
|
+
source: 'customer',
|
|
137
|
+
target: 'cloud.frontend.dashboard',
|
|
138
|
+
title: ''
|
|
139
|
+
},
|
|
140
|
+
'support:cloud.frontend.adminPanel': {
|
|
141
|
+
id: 'support:cloud.frontend.adminPanel',
|
|
142
|
+
source: 'support',
|
|
143
|
+
target: 'cloud.frontend.adminPanel',
|
|
144
|
+
title: ''
|
|
145
|
+
},
|
|
146
|
+
'cloud.backend.storage:amazon.s3': {
|
|
147
|
+
id: 'cloud.backend.storage:amazon.s3',
|
|
148
|
+
source: 'cloud.backend.storage',
|
|
149
|
+
target: 'amazon.s3',
|
|
150
|
+
title: ''
|
|
151
|
+
},
|
|
152
|
+
'cloud.backend.graphql:cloud.backend.storage': {
|
|
153
|
+
id: 'cloud.backend.graphql:cloud.backend.storage',
|
|
154
|
+
source: 'cloud.backend.graphql',
|
|
155
|
+
target: 'cloud.backend.storage',
|
|
156
|
+
title: ''
|
|
157
|
+
},
|
|
158
|
+
'cloud.frontend.dashboard:cloud.backend.graphql': {
|
|
159
|
+
id: 'cloud.frontend.dashboard:cloud.backend.graphql',
|
|
160
|
+
source: 'cloud.frontend.dashboard',
|
|
161
|
+
target: 'cloud.backend.graphql',
|
|
162
|
+
title: ''
|
|
163
|
+
},
|
|
164
|
+
'cloud.frontend.adminPanel:cloud.backend.graphql': {
|
|
165
|
+
id: 'cloud.frontend.adminPanel:cloud.backend.graphql',
|
|
166
|
+
source: 'cloud.frontend.adminPanel',
|
|
167
|
+
target: 'cloud.backend.graphql',
|
|
168
|
+
title: ''
|
|
169
|
+
}
|
|
170
|
+
};
|
|
171
|
+
export const fakeElementView = {
|
|
172
|
+
id: 'fakeView',
|
|
173
|
+
title: '',
|
|
174
|
+
viewOf: 'cloud',
|
|
175
|
+
rules: [
|
|
176
|
+
{
|
|
177
|
+
isInclude: true,
|
|
178
|
+
exprs: [{ wildcard: true }]
|
|
179
|
+
}
|
|
180
|
+
]
|
|
181
|
+
};
|
|
182
|
+
export const fakeModel = () => ModelIndex.from({
|
|
183
|
+
elements: fakeElements,
|
|
184
|
+
relations: fakeRelations,
|
|
185
|
+
views: {
|
|
186
|
+
[fakeElementView.id]: fakeElementView
|
|
187
|
+
}
|
|
188
|
+
});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './data';
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type { Fqn, Relation } from '../types';
|
|
2
|
+
import type { ComputedEdge } from '../types/computed-view';
|
|
3
|
+
export declare class EdgeBuilder {
|
|
4
|
+
private _relationsObj;
|
|
5
|
+
add(source: Fqn, target: Fqn, relation: Relation): this;
|
|
6
|
+
build(): ComputedEdge[];
|
|
7
|
+
}
|
|
8
|
+
//# sourceMappingURL=EdgeBuilder.d.ts.map
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { equals, head, keys, pluck, reject } from 'rambdax';
|
|
2
|
+
import { commonAncestor, compareFqnHierarchically } from '../utils/fqn';
|
|
3
|
+
import { compareRelations } from '../utils/relations';
|
|
4
|
+
export class EdgeBuilder {
|
|
5
|
+
_relationsObj = {};
|
|
6
|
+
add(source, target, relation) {
|
|
7
|
+
const bySource = this._relationsObj[source] ?? {};
|
|
8
|
+
const relations = bySource[target] ?? [];
|
|
9
|
+
relations.push(relation);
|
|
10
|
+
bySource[target] = relations;
|
|
11
|
+
this._relationsObj[source] = bySource;
|
|
12
|
+
return this;
|
|
13
|
+
}
|
|
14
|
+
build() {
|
|
15
|
+
return keys(this._relationsObj)
|
|
16
|
+
.flatMap(source => {
|
|
17
|
+
const targets = this._relationsObj[source] ?? {};
|
|
18
|
+
return keys(targets).map(target => {
|
|
19
|
+
const relations = (targets[target] ?? []).sort(compareRelations);
|
|
20
|
+
const label = head(reject(equals(''), pluck('title', relations))) ?? null;
|
|
21
|
+
return {
|
|
22
|
+
id: `${source}:${target}`,
|
|
23
|
+
parent: commonAncestor(source, target),
|
|
24
|
+
source,
|
|
25
|
+
target,
|
|
26
|
+
label,
|
|
27
|
+
relations: pluck('id', relations)
|
|
28
|
+
};
|
|
29
|
+
});
|
|
30
|
+
})
|
|
31
|
+
.sort(compareRelations)
|
|
32
|
+
.reverse();
|
|
33
|
+
}
|
|
34
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { ModelIndex } from '../model-index';
|
|
2
|
+
import type { Element, ElementView, Fqn, LikeC4Model, Relation, RelationID, ViewID } from '../types';
|
|
3
|
+
import type { ComputedView } from '../types/computed-view';
|
|
4
|
+
export declare function computeView(view: ElementView, index: ModelIndex): ComputedView;
|
|
5
|
+
type InputModel = {
|
|
6
|
+
elements: Record<Fqn, Element>;
|
|
7
|
+
relations: Record<RelationID, Relation>;
|
|
8
|
+
views: Record<ViewID, ElementView>;
|
|
9
|
+
};
|
|
10
|
+
export declare function computeViews(model: InputModel): LikeC4Model;
|
|
11
|
+
export {};
|
|
12
|
+
//# sourceMappingURL=compute.d.ts.map
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import type { ModelIndex } from '../model-index';
|
|
2
|
+
import { type ElementView } from '../types';
|
|
3
|
+
import type { ComputedView } from '../types/computed-view';
|
|
4
|
+
export declare function computeElementView(view: ElementView, index: ModelIndex): ComputedView;
|
|
5
|
+
//# sourceMappingURL=compute.element-view.d.ts.map
|
|
@@ -0,0 +1,168 @@
|
|
|
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
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { map } from 'rambdax';
|
|
2
|
+
import { ModelIndex } from '../model-index';
|
|
3
|
+
import { computeElementView } from './compute.element-view';
|
|
4
|
+
export function computeView(view, index) {
|
|
5
|
+
return computeElementView(view, index);
|
|
6
|
+
}
|
|
7
|
+
export function computeViews(model) {
|
|
8
|
+
const index = ModelIndex.from(model);
|
|
9
|
+
return {
|
|
10
|
+
elements: model.elements,
|
|
11
|
+
relations: model.relations,
|
|
12
|
+
views: map(v => computeElementView(v, index), model.views)
|
|
13
|
+
};
|
|
14
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { computeView, computeViews } from './compute';
|
|
@@ -0,0 +1,12 @@
|
|
|
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
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
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
|