@likec4/language-server 1.17.1 → 1.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/contrib/likec4.tmLanguage.json +1 -1
- package/dist/browser.cjs +1 -1
- package/dist/browser.d.cts +2 -2
- package/dist/browser.d.mts +2 -2
- package/dist/browser.d.ts +2 -2
- package/dist/browser.mjs +2 -2
- package/dist/index.cjs +1 -1
- package/dist/index.d.cts +2 -2
- package/dist/index.d.mts +2 -2
- package/dist/index.d.ts +2 -2
- package/dist/index.mjs +2 -2
- package/dist/protocol.d.cts +8 -5
- package/dist/protocol.d.mts +8 -5
- package/dist/protocol.d.ts +8 -5
- package/dist/shared/{language-server.DKV_FdPN.cjs → language-server.CO_nmHiL.cjs} +5598 -4213
- package/dist/shared/{language-server.BQRvVmE0.d.cts → language-server.Da6ey08o.d.cts} +390 -74
- package/dist/shared/{language-server.BysPcTxr.d.ts → language-server.De7S3e5Z.d.ts} +390 -74
- package/dist/shared/{language-server._wkyPgso.d.mts → language-server.Dj4iDjtB.d.mts} +390 -74
- package/dist/shared/{language-server.BIbAD1T-.mjs → language-server.oO_9JoAG.mjs} +5604 -4230
- package/package.json +11 -25
- package/src/Rpc.ts +6 -3
- package/src/ast.ts +124 -71
- package/src/generated/ast.ts +655 -39
- package/src/generated/grammar.ts +1 -1
- package/src/index.ts +1 -0
- package/src/like-c4.langium +170 -22
- package/src/logger.ts +7 -2
- package/src/lsp/CodeLensProvider.ts +0 -1
- package/src/lsp/CompletionProvider.ts +17 -2
- package/src/lsp/DocumentSymbolProvider.ts +5 -2
- package/src/lsp/HoverProvider.ts +34 -2
- package/src/lsp/SemanticTokenProvider.ts +58 -32
- package/src/model/deployments-index.ts +218 -0
- package/src/model/fqn-computation.ts +1 -1
- package/src/model/fqn-index.ts +0 -1
- package/src/model/index.ts +1 -0
- package/src/model/model-builder.ts +172 -37
- package/src/model/model-locator.ts +36 -7
- package/src/model/model-parser.ts +554 -92
- package/src/model-change/changeViewLayout.ts +2 -2
- package/src/module.ts +10 -4
- package/src/protocol.ts +10 -6
- package/src/references/index.ts +1 -0
- package/src/references/name-provider.ts +37 -0
- package/src/references/scope-computation.ts +130 -21
- package/src/references/scope-provider.ts +63 -36
- package/src/shared/NodeKindProvider.ts +15 -3
- package/src/utils/deploymentRef.ts +31 -0
- package/src/{elementRef.ts → utils/elementRef.ts} +1 -1
- package/src/utils/stringHash.ts +2 -2
- package/src/validation/_shared.ts +7 -5
- package/src/validation/deployment-checks.ts +144 -0
- package/src/validation/dynamic-view-step.ts +1 -1
- package/src/validation/index.ts +7 -0
- package/src/validation/relation.ts +1 -1
- package/src/validation/view-predicates/deployments.ts +56 -0
- package/src/validation/view-predicates/index.ts +1 -0
- package/src/view-utils/assignNavigateTo.ts +6 -5
- package/src/view-utils/index.ts +0 -1
- package/dist/model-graph/index.cjs +0 -10
- package/dist/model-graph/index.d.cts +0 -81
- package/dist/model-graph/index.d.mts +0 -81
- package/dist/model-graph/index.d.ts +0 -81
- package/dist/model-graph/index.mjs +0 -1
- package/dist/shared/language-server.D2QdbOJO.cjs +0 -1995
- package/dist/shared/language-server.DGrBGmsd.mjs +0 -1981
- package/src/model-graph/LikeC4ModelGraph.ts +0 -338
- package/src/model-graph/compute-view/__test__/fixture.ts +0 -630
- package/src/model-graph/compute-view/compute.ts +0 -788
- package/src/model-graph/compute-view/index.ts +0 -33
- package/src/model-graph/compute-view/predicates.ts +0 -509
- package/src/model-graph/dynamic-view/__test__/fixture.ts +0 -61
- package/src/model-graph/dynamic-view/compute.ts +0 -313
- package/src/model-graph/dynamic-view/index.ts +0 -29
- package/src/model-graph/index.ts +0 -3
- package/src/model-graph/utils/applyCustomElementProperties.ts +0 -65
- package/src/model-graph/utils/applyCustomRelationProperties.ts +0 -41
- package/src/model-graph/utils/applyViewRuleStyles.ts +0 -49
- package/src/model-graph/utils/buildComputeNodes.ts +0 -113
- package/src/model-graph/utils/buildElementNotations.ts +0 -63
- package/src/model-graph/utils/elementExpressionToPredicate.ts +0 -39
- package/src/model-graph/utils/relationExpressionToPredicates.ts +0 -43
- package/src/model-graph/utils/sortNodes.ts +0 -105
- package/src/model-graph/utils/uniqueTags.test.ts +0 -42
- package/src/model-graph/utils/uniqueTags.ts +0 -19
- package/src/utils/graphlib.ts +0 -9
- package/src/view-utils/resolve-extended-views.ts +0 -66
- package/src/view-utils/resolve-global-rules.ts +0 -88
- package/src/view-utils/view-hash.ts +0 -27
|
@@ -1,33 +0,0 @@
|
|
|
1
|
-
import { type ComputedElementView, type ElementView } from '@likec4/core'
|
|
2
|
-
import type { LikeC4ModelGraph } from '../LikeC4ModelGraph'
|
|
3
|
-
import { ComputeCtx } from './compute'
|
|
4
|
-
|
|
5
|
-
export function computeElementView(view: ElementView, graph: LikeC4ModelGraph) {
|
|
6
|
-
return ComputeCtx.elementView(view, graph)
|
|
7
|
-
}
|
|
8
|
-
|
|
9
|
-
type ComputeViewResult =
|
|
10
|
-
| {
|
|
11
|
-
isSuccess: true
|
|
12
|
-
view: ComputedElementView
|
|
13
|
-
}
|
|
14
|
-
| {
|
|
15
|
-
isSuccess: false
|
|
16
|
-
error: Error
|
|
17
|
-
view: undefined
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
export function computeView(view: ElementView, graph: LikeC4ModelGraph): ComputeViewResult {
|
|
21
|
-
try {
|
|
22
|
-
return {
|
|
23
|
-
isSuccess: true,
|
|
24
|
-
view: computeElementView(view, graph)
|
|
25
|
-
}
|
|
26
|
-
} catch (e) {
|
|
27
|
-
return {
|
|
28
|
-
isSuccess: false,
|
|
29
|
-
error: e instanceof Error ? e : new Error(`Unknown error: ${e}`),
|
|
30
|
-
view: undefined
|
|
31
|
-
}
|
|
32
|
-
}
|
|
33
|
-
}
|
|
@@ -1,509 +0,0 @@
|
|
|
1
|
-
import type { Element, Relation } from '@likec4/core'
|
|
2
|
-
import { Expr, isAncestor, nonexhaustive, parentFqn } from '@likec4/core'
|
|
3
|
-
import { allPass, filter as remedaFilter, flatMap, isNullish as isNil, map, pipe, unique } from 'remeda'
|
|
4
|
-
import { elementExprToPredicate } from '../utils/elementExpressionToPredicate'
|
|
5
|
-
import type { ComputeCtx } from './compute'
|
|
6
|
-
|
|
7
|
-
type Predicate<T> = (x: T) => boolean
|
|
8
|
-
export type ElementPredicateFn = Predicate<Element>
|
|
9
|
-
export type RelationPredicateFn = Predicate<Relation>
|
|
10
|
-
// // type ElementPredicate = Predicate<Element>
|
|
11
|
-
// type ElementPredicates<T> = T extends Element[] ? (x: T) => T : (T extends Element ? (x: T) => (Element | null) : never)
|
|
12
|
-
// type ElementPredicate = ElementPredicates<Element | Element[]>
|
|
13
|
-
|
|
14
|
-
const NoFilter: ElementPredicateFn = () => true
|
|
15
|
-
const Identity = <T>(x: T) => x
|
|
16
|
-
const filterBy = <T>(pred: Predicate<T>) => pred === NoFilter ? Identity : remedaFilter(pred)
|
|
17
|
-
const filterOne = <T>(pred: Predicate<T>) => pred === NoFilter ? Identity : (x: T) => pred(x) ? x : null
|
|
18
|
-
|
|
19
|
-
export function includeElementRef(this: ComputeCtx, expr: Expr.ElementRefExpr, where = NoFilter) {
|
|
20
|
-
// Get the elements that are already in the Ctx before any mutations
|
|
21
|
-
// Because we need to add edges between them and the new elements
|
|
22
|
-
const currentElements = [...this.resolvedElements]
|
|
23
|
-
const filter = filterBy(where)
|
|
24
|
-
|
|
25
|
-
const elements = filter(
|
|
26
|
-
expr.isDescedants === true
|
|
27
|
-
? this.graph.childrenOrElement(expr.element)
|
|
28
|
-
: [this.graph.element(expr.element)]
|
|
29
|
-
)
|
|
30
|
-
if (elements.length === 0) {
|
|
31
|
-
return
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
this.addElement(...elements)
|
|
35
|
-
|
|
36
|
-
if (elements.length > 1) {
|
|
37
|
-
this.addEdges(this.graph.edgesWithin(elements))
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
if (currentElements.length > 0 && elements.length > 0) {
|
|
41
|
-
for (const el of elements) {
|
|
42
|
-
this.addEdges(this.graph.anyEdgesBetween(el, currentElements))
|
|
43
|
-
}
|
|
44
|
-
}
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
export function excludeElementRef(this: ComputeCtx, expr: Expr.ElementRefExpr, where = NoFilter) {
|
|
48
|
-
const elements = [...this.resolvedElements].filter(allPass([
|
|
49
|
-
elementExprToPredicate(expr),
|
|
50
|
-
where
|
|
51
|
-
]))
|
|
52
|
-
this.excludeElement(...elements)
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
export function includeWildcardRef(this: ComputeCtx, _expr: Expr.WildcardExpr, where = NoFilter) {
|
|
56
|
-
const root = this.root
|
|
57
|
-
if (!root) {
|
|
58
|
-
// Take root elements
|
|
59
|
-
const elements = this.graph.rootElements.filter(where)
|
|
60
|
-
if (elements.length <= 0) {
|
|
61
|
-
return
|
|
62
|
-
}
|
|
63
|
-
const currentElements = [...this.resolvedElements]
|
|
64
|
-
this.addElement(...elements)
|
|
65
|
-
this.addEdges(this.graph.edgesWithin(elements))
|
|
66
|
-
if (currentElements.length > 0) {
|
|
67
|
-
for (const el of elements) {
|
|
68
|
-
this.addEdges(this.graph.anyEdgesBetween(el, currentElements))
|
|
69
|
-
}
|
|
70
|
-
}
|
|
71
|
-
return
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
const currentElements = [...this.resolvedElements]
|
|
75
|
-
const _elRoot = filterOne(where)(this.graph.element(root))
|
|
76
|
-
if (_elRoot) {
|
|
77
|
-
this.addElement(_elRoot)
|
|
78
|
-
}
|
|
79
|
-
const filter = filterBy(where)
|
|
80
|
-
|
|
81
|
-
const children = filter(this.graph.children(root))
|
|
82
|
-
const hasChildren = children.length > 0
|
|
83
|
-
if (hasChildren) {
|
|
84
|
-
this.addElement(...children)
|
|
85
|
-
this.addEdges(this.graph.edgesWithin(children))
|
|
86
|
-
} else if (_elRoot) {
|
|
87
|
-
children.push(_elRoot)
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
// All neighbours that may have relations with root or its children
|
|
91
|
-
const neighbours = [
|
|
92
|
-
...currentElements,
|
|
93
|
-
...filter([
|
|
94
|
-
...this.graph.siblings(root),
|
|
95
|
-
...this.graph.ancestors(root).flatMap(a => this.graph.siblings(a.id))
|
|
96
|
-
])
|
|
97
|
-
]
|
|
98
|
-
|
|
99
|
-
for (const el of children) {
|
|
100
|
-
this.addEdges(this.graph.anyEdgesBetween(el, neighbours)).forEach(edge => {
|
|
101
|
-
this.addImplicit(edge.source, edge.target)
|
|
102
|
-
})
|
|
103
|
-
}
|
|
104
|
-
|
|
105
|
-
// If root has no children
|
|
106
|
-
if (!hasChildren && _elRoot) {
|
|
107
|
-
// Any edges with siblings?
|
|
108
|
-
const edgesWithSiblings = this.graph.anyEdgesBetween(_elRoot, this.graph.siblings(root))
|
|
109
|
-
if (edgesWithSiblings.length === 0) {
|
|
110
|
-
// If no edges with siblings, i.e. root is orphan
|
|
111
|
-
// Lets add parent for better view
|
|
112
|
-
const _parentId = parentFqn(root)
|
|
113
|
-
const parent = _parentId && this.graph.element(_parentId)
|
|
114
|
-
if (parent && where(parent)) {
|
|
115
|
-
this.addElement(parent)
|
|
116
|
-
}
|
|
117
|
-
}
|
|
118
|
-
}
|
|
119
|
-
}
|
|
120
|
-
|
|
121
|
-
export function excludeWildcardRef(this: ComputeCtx, _expr: Expr.WildcardExpr, where = NoFilter) {
|
|
122
|
-
if (where !== NoFilter) {
|
|
123
|
-
const elements = [...this.resolvedElements].filter(where)
|
|
124
|
-
this.excludeElement(...elements)
|
|
125
|
-
return
|
|
126
|
-
}
|
|
127
|
-
const root = this.root
|
|
128
|
-
if (root) {
|
|
129
|
-
this.excludeElement(
|
|
130
|
-
this.graph.element(root),
|
|
131
|
-
...this.graph.children(root)
|
|
132
|
-
)
|
|
133
|
-
this.excludeRelation(
|
|
134
|
-
...this.graph.connectedRelations(root)
|
|
135
|
-
)
|
|
136
|
-
} else {
|
|
137
|
-
this.reset()
|
|
138
|
-
}
|
|
139
|
-
}
|
|
140
|
-
|
|
141
|
-
export function includeExpandedElementExpr(
|
|
142
|
-
this: ComputeCtx,
|
|
143
|
-
expr: Expr.ExpandedElementExpr,
|
|
144
|
-
where = NoFilter
|
|
145
|
-
) {
|
|
146
|
-
const filter = filterBy(where)
|
|
147
|
-
const currentElements = [...this.resolvedElements]
|
|
148
|
-
|
|
149
|
-
// Always add parent
|
|
150
|
-
const parent = this.graph.element(expr.expanded)
|
|
151
|
-
if (where(parent)) {
|
|
152
|
-
this.addElement(parent)
|
|
153
|
-
const anyEdgesBetween = this.graph.anyEdgesBetween(parent, currentElements)
|
|
154
|
-
this.addEdges(anyEdgesBetween)
|
|
155
|
-
}
|
|
156
|
-
|
|
157
|
-
const expanded = [] as Element[]
|
|
158
|
-
|
|
159
|
-
for (const el of filter(this.graph.children(expr.expanded))) {
|
|
160
|
-
this.addImplicit(el)
|
|
161
|
-
const edges = this.graph.anyEdgesBetween(el, currentElements)
|
|
162
|
-
if (edges.length > 0) {
|
|
163
|
-
this.addEdges(edges)
|
|
164
|
-
expanded.push(el)
|
|
165
|
-
}
|
|
166
|
-
}
|
|
167
|
-
if (expanded.length > 1) {
|
|
168
|
-
this.addEdges(this.graph.edgesWithin(expanded))
|
|
169
|
-
}
|
|
170
|
-
}
|
|
171
|
-
|
|
172
|
-
export function excludeExpandedElementExpr(
|
|
173
|
-
this: ComputeCtx,
|
|
174
|
-
expr: Expr.ExpandedElementExpr,
|
|
175
|
-
where = NoFilter
|
|
176
|
-
) {
|
|
177
|
-
const elements = [...this.resolvedElements].filter(allPass([
|
|
178
|
-
elementExprToPredicate(expr),
|
|
179
|
-
where
|
|
180
|
-
]))
|
|
181
|
-
this.excludeElement(...elements)
|
|
182
|
-
}
|
|
183
|
-
|
|
184
|
-
const asElementPredicate = (
|
|
185
|
-
expr: Expr.ElementKindExpr | Expr.ElementTagExpr
|
|
186
|
-
): Predicate<Element> => {
|
|
187
|
-
if (expr.isEqual) {
|
|
188
|
-
if (Expr.isElementKindExpr(expr)) {
|
|
189
|
-
return e => e.kind === expr.elementKind
|
|
190
|
-
} else {
|
|
191
|
-
return ({ tags }) => !!tags && tags.includes(expr.elementTag)
|
|
192
|
-
}
|
|
193
|
-
} else {
|
|
194
|
-
if (Expr.isElementKindExpr(expr)) {
|
|
195
|
-
return e => e.kind !== expr.elementKind
|
|
196
|
-
} else {
|
|
197
|
-
return ({ tags }) => isNil(tags) || tags.length === 0 || !tags.includes(expr.elementTag)
|
|
198
|
-
}
|
|
199
|
-
}
|
|
200
|
-
}
|
|
201
|
-
export function includeElementKindOrTag(
|
|
202
|
-
this: ComputeCtx,
|
|
203
|
-
expr: Expr.ElementKindExpr | Expr.ElementTagExpr,
|
|
204
|
-
where = NoFilter
|
|
205
|
-
) {
|
|
206
|
-
const elements = this.graph.elements.filter(asElementPredicate(expr)).filter(where)
|
|
207
|
-
if (elements.length > 0) {
|
|
208
|
-
const currentElements = [...this.resolvedElements]
|
|
209
|
-
this.addElement(...elements)
|
|
210
|
-
this.addEdges(this.graph.edgesWithin(elements))
|
|
211
|
-
for (const el of elements) {
|
|
212
|
-
this.addEdges(this.graph.anyEdgesBetween(el, currentElements))
|
|
213
|
-
}
|
|
214
|
-
}
|
|
215
|
-
}
|
|
216
|
-
|
|
217
|
-
export function excludeElementKindOrTag(
|
|
218
|
-
this: ComputeCtx,
|
|
219
|
-
expr: Expr.ElementKindExpr | Expr.ElementTagExpr,
|
|
220
|
-
where = NoFilter
|
|
221
|
-
) {
|
|
222
|
-
const elements = [...this.resolvedElements].filter(asElementPredicate(expr)).filter(where)
|
|
223
|
-
if (elements.length > 0) {
|
|
224
|
-
this.excludeElement(...elements)
|
|
225
|
-
}
|
|
226
|
-
}
|
|
227
|
-
|
|
228
|
-
function resolveNeighbours(this: ComputeCtx, expr: Expr.ElementExpression): Element[] {
|
|
229
|
-
if (Expr.isElementRef(expr)) {
|
|
230
|
-
return this.graph.ascendingSiblings(expr.element)
|
|
231
|
-
}
|
|
232
|
-
return this.root ? this.graph.ascendingSiblings(this.root) : this.graph.rootElements
|
|
233
|
-
}
|
|
234
|
-
|
|
235
|
-
function resolveElements(this: ComputeCtx, expr: Expr.ElementExpression): Element[] {
|
|
236
|
-
if (Expr.isWildcard(expr)) {
|
|
237
|
-
if (this.root) {
|
|
238
|
-
return [...this.graph.children(this.root), this.graph.element(this.root)]
|
|
239
|
-
} else {
|
|
240
|
-
return this.graph.rootElements
|
|
241
|
-
}
|
|
242
|
-
}
|
|
243
|
-
if (Expr.isElementKindExpr(expr)) {
|
|
244
|
-
return this.graph.elements.filter(el => {
|
|
245
|
-
if (expr.isEqual) {
|
|
246
|
-
return el.kind === expr.elementKind
|
|
247
|
-
}
|
|
248
|
-
return el.kind !== expr.elementKind
|
|
249
|
-
})
|
|
250
|
-
}
|
|
251
|
-
if (Expr.isElementTagExpr(expr)) {
|
|
252
|
-
return this.graph.elements.filter(el => {
|
|
253
|
-
const tags = el.tags
|
|
254
|
-
if (expr.isEqual) {
|
|
255
|
-
return !!tags && tags.includes(expr.elementTag)
|
|
256
|
-
}
|
|
257
|
-
return isNil(tags) || tags.length === 0 || !tags.includes(expr.elementTag)
|
|
258
|
-
})
|
|
259
|
-
}
|
|
260
|
-
if (Expr.isExpandedElementExpr(expr)) {
|
|
261
|
-
return [this.graph.element(expr.expanded)]
|
|
262
|
-
}
|
|
263
|
-
|
|
264
|
-
// Type guard
|
|
265
|
-
if (!Expr.isElementRef(expr)) {
|
|
266
|
-
return nonexhaustive(expr)
|
|
267
|
-
}
|
|
268
|
-
|
|
269
|
-
if (this.root === expr.element && expr.isDescedants !== true) {
|
|
270
|
-
return [...this.graph.children(this.root), this.graph.element(this.root)]
|
|
271
|
-
}
|
|
272
|
-
|
|
273
|
-
if (expr.isDescedants) {
|
|
274
|
-
return this.graph.childrenOrElement(expr.element)
|
|
275
|
-
} else {
|
|
276
|
-
return [this.graph.element(expr.element)]
|
|
277
|
-
}
|
|
278
|
-
}
|
|
279
|
-
|
|
280
|
-
// --------------------------------
|
|
281
|
-
// Incoming Expr
|
|
282
|
-
|
|
283
|
-
function edgesIncomingExpr(this: ComputeCtx, expr: Expr.ElementExpression) {
|
|
284
|
-
if (Expr.isWildcard(expr)) {
|
|
285
|
-
if (!this.root) {
|
|
286
|
-
return []
|
|
287
|
-
}
|
|
288
|
-
const sources = this.graph.ascendingSiblings(this.root)
|
|
289
|
-
const targets = [...this.graph.children(this.root), this.graph.element(this.root)]
|
|
290
|
-
return this.graph.edgesBetween(sources, targets)
|
|
291
|
-
}
|
|
292
|
-
const targets = resolveElements.call(this, expr)
|
|
293
|
-
if (targets.length === 0) {
|
|
294
|
-
return []
|
|
295
|
-
}
|
|
296
|
-
let sources = [...this.resolvedElements]
|
|
297
|
-
if (Expr.isElementRef(expr) || Expr.isExpandedElementExpr(expr)) {
|
|
298
|
-
const exprElement = expr.element ?? expr.expanded
|
|
299
|
-
const isDescedants = expr.isDescedants ?? false
|
|
300
|
-
sources = sources.filter(el =>
|
|
301
|
-
// allow elements, that are not nested or are direct children
|
|
302
|
-
!isAncestor(exprElement, el.id) || (isDescedants && parentFqn(el.id) === exprElement)
|
|
303
|
-
)
|
|
304
|
-
}
|
|
305
|
-
if (sources.length === 0) {
|
|
306
|
-
sources = resolveNeighbours.call(this, expr)
|
|
307
|
-
}
|
|
308
|
-
return this.graph.edgesBetween(sources, targets)
|
|
309
|
-
}
|
|
310
|
-
|
|
311
|
-
const filterEdges = (edges: ReadonlyArray<ComputeCtx.Edge>, where?: RelationPredicateFn) => {
|
|
312
|
-
if (!where) {
|
|
313
|
-
return edges as ComputeCtx.Edge[]
|
|
314
|
-
}
|
|
315
|
-
return pipe(
|
|
316
|
-
edges,
|
|
317
|
-
map(e => ({ ...e, relations: e.relations.filter(where) })),
|
|
318
|
-
remedaFilter(e => e.relations.length > 0)
|
|
319
|
-
) as ComputeCtx.Edge[]
|
|
320
|
-
}
|
|
321
|
-
|
|
322
|
-
const filterRelations = (edges: ComputeCtx.Edge[], where?: RelationPredicateFn) => {
|
|
323
|
-
return pipe(
|
|
324
|
-
edges,
|
|
325
|
-
flatMap(e => e.relations),
|
|
326
|
-
where ? remedaFilter(where) : Identity,
|
|
327
|
-
unique()
|
|
328
|
-
)
|
|
329
|
-
}
|
|
330
|
-
|
|
331
|
-
export function includeIncomingExpr(this: ComputeCtx, expr: Expr.IncomingExpr, where?: RelationPredicateFn) {
|
|
332
|
-
const edges = filterEdges(edgesIncomingExpr.call(this, expr.incoming), where)
|
|
333
|
-
if (edges.length === 0) {
|
|
334
|
-
return
|
|
335
|
-
}
|
|
336
|
-
this.addEdges(edges).forEach(edge => {
|
|
337
|
-
this.addImplicit(edge.target)
|
|
338
|
-
})
|
|
339
|
-
}
|
|
340
|
-
export function excludeIncomingExpr(this: ComputeCtx, expr: Expr.IncomingExpr, where?: RelationPredicateFn) {
|
|
341
|
-
let relations = filterRelations(edgesIncomingExpr.call(this, expr.incoming), where)
|
|
342
|
-
this.excludeRelation(...relations)
|
|
343
|
-
}
|
|
344
|
-
|
|
345
|
-
// --------------------------------
|
|
346
|
-
// Outgoing Expr
|
|
347
|
-
|
|
348
|
-
function edgesOutgoingExpr(this: ComputeCtx, expr: Expr.ElementExpression) {
|
|
349
|
-
if (Expr.isWildcard(expr)) {
|
|
350
|
-
if (!this.root) {
|
|
351
|
-
return []
|
|
352
|
-
}
|
|
353
|
-
const targets = this.graph.ascendingSiblings(this.root)
|
|
354
|
-
const sources = [...this.graph.children(this.root), this.graph.element(this.root)]
|
|
355
|
-
return this.graph.edgesBetween(sources, targets)
|
|
356
|
-
}
|
|
357
|
-
const sources = resolveElements.call(this, expr)
|
|
358
|
-
if (sources.length === 0) {
|
|
359
|
-
return []
|
|
360
|
-
}
|
|
361
|
-
let targets = [...this.resolvedElements]
|
|
362
|
-
if (Expr.isElementRef(expr) || Expr.isExpandedElementExpr(expr)) {
|
|
363
|
-
const sourceElement = expr.element ?? expr.expanded
|
|
364
|
-
const isDescedants = expr.isDescedants ?? false
|
|
365
|
-
targets = targets.filter(el =>
|
|
366
|
-
// allow elements, that are not nested or are direct children
|
|
367
|
-
!isAncestor(sourceElement, el.id) || (isDescedants && parentFqn(el.id) === sourceElement)
|
|
368
|
-
)
|
|
369
|
-
}
|
|
370
|
-
if (targets.length === 0) {
|
|
371
|
-
targets = resolveNeighbours.call(this, expr)
|
|
372
|
-
}
|
|
373
|
-
return this.graph.edgesBetween(sources, targets)
|
|
374
|
-
}
|
|
375
|
-
|
|
376
|
-
export function includeOutgoingExpr(this: ComputeCtx, expr: Expr.OutgoingExpr, where?: RelationPredicateFn) {
|
|
377
|
-
const edges = filterEdges(edgesOutgoingExpr.call(this, expr.outgoing), where)
|
|
378
|
-
if (edges.length === 0) {
|
|
379
|
-
return
|
|
380
|
-
}
|
|
381
|
-
this.addEdges(edges).forEach(edge => {
|
|
382
|
-
this.addImplicit(edge.source)
|
|
383
|
-
})
|
|
384
|
-
}
|
|
385
|
-
export function excludeOutgoingExpr(this: ComputeCtx, expr: Expr.OutgoingExpr, where?: RelationPredicateFn) {
|
|
386
|
-
const relations = filterRelations(edgesOutgoingExpr.call(this, expr.outgoing), where)
|
|
387
|
-
this.excludeRelation(...relations)
|
|
388
|
-
}
|
|
389
|
-
|
|
390
|
-
// --------------------------------
|
|
391
|
-
// InOut Expr
|
|
392
|
-
type EdgePredicateResult = {
|
|
393
|
-
implicits: Element[]
|
|
394
|
-
edges: ComputeCtx.Edge[]
|
|
395
|
-
}
|
|
396
|
-
|
|
397
|
-
namespace EdgePredicateResult {
|
|
398
|
-
export const Empty: EdgePredicateResult = {
|
|
399
|
-
implicits: [],
|
|
400
|
-
edges: []
|
|
401
|
-
}
|
|
402
|
-
}
|
|
403
|
-
function edgesInOutExpr(this: ComputeCtx, { inout }: Expr.InOutExpr, where?: RelationPredicateFn): EdgePredicateResult {
|
|
404
|
-
if (Expr.isWildcard(inout)) {
|
|
405
|
-
if (!this.root) {
|
|
406
|
-
return EdgePredicateResult.Empty
|
|
407
|
-
}
|
|
408
|
-
const neighbours = this.graph.ascendingSiblings(this.root)
|
|
409
|
-
return {
|
|
410
|
-
edges: filterEdges(this.graph.anyEdgesBetween(this.graph.element(this.root), neighbours), where),
|
|
411
|
-
implicits: []
|
|
412
|
-
}
|
|
413
|
-
}
|
|
414
|
-
const elements = resolveElements.call(this, inout)
|
|
415
|
-
if (elements.length === 0) {
|
|
416
|
-
return EdgePredicateResult.Empty
|
|
417
|
-
}
|
|
418
|
-
let currentElements = [...this.resolvedElements]
|
|
419
|
-
|
|
420
|
-
if (Expr.isElementRef(inout) || Expr.isExpandedElementExpr(inout)) {
|
|
421
|
-
const exprElement = inout.element ?? inout.expanded
|
|
422
|
-
const isDescedants = inout.isDescedants ?? false
|
|
423
|
-
currentElements = currentElements.filter(el =>
|
|
424
|
-
// allow elements, that are not nested or are direct children
|
|
425
|
-
!isAncestor(exprElement, el.id) || (isDescedants && parentFqn(el.id) === exprElement)
|
|
426
|
-
)
|
|
427
|
-
}
|
|
428
|
-
if (currentElements.length === 0) {
|
|
429
|
-
currentElements = resolveNeighbours.call(this, inout)
|
|
430
|
-
}
|
|
431
|
-
return elements.reduce<EdgePredicateResult>((acc, el) => {
|
|
432
|
-
const edges = filterEdges(this.graph.anyEdgesBetween(el, currentElements), where)
|
|
433
|
-
if (edges.length > 0) {
|
|
434
|
-
acc.implicits.push(el)
|
|
435
|
-
acc.edges.push(...edges)
|
|
436
|
-
}
|
|
437
|
-
return acc
|
|
438
|
-
}, { implicits: [], edges: [] })
|
|
439
|
-
}
|
|
440
|
-
|
|
441
|
-
export function includeInOutExpr(this: ComputeCtx, expr: Expr.InOutExpr, where?: RelationPredicateFn) {
|
|
442
|
-
const { implicits, edges } = edgesInOutExpr.call(this, expr, where)
|
|
443
|
-
this.addEdges(edges)
|
|
444
|
-
this.addImplicit(...implicits)
|
|
445
|
-
}
|
|
446
|
-
export function excludeInOutExpr(this: ComputeCtx, expr: Expr.InOutExpr, where?: RelationPredicateFn) {
|
|
447
|
-
const { edges } = edgesInOutExpr.call(this, expr, where)
|
|
448
|
-
this.excludeRelation(...edges.flatMap(e => e.relations))
|
|
449
|
-
}
|
|
450
|
-
|
|
451
|
-
/**
|
|
452
|
-
* Expand element to its children and itself, if it is the root (and not ".*")
|
|
453
|
-
* Example:
|
|
454
|
-
*
|
|
455
|
-
* view of api {
|
|
456
|
-
* include some -> api
|
|
457
|
-
* }
|
|
458
|
-
*
|
|
459
|
-
* Transform to:
|
|
460
|
-
*
|
|
461
|
-
* view of api {
|
|
462
|
-
* include some -> api.*, some -> api
|
|
463
|
-
* }
|
|
464
|
-
*/
|
|
465
|
-
function resolveRelationExprElements(this: ComputeCtx, expr: Expr.ElementExpression) {
|
|
466
|
-
if (Expr.isElementRef(expr) && this.root === expr.element && expr.isDescedants !== true) {
|
|
467
|
-
return [...this.graph.children(expr.element), this.graph.element(expr.element)]
|
|
468
|
-
}
|
|
469
|
-
if (Expr.isExpandedElementExpr(expr) && this.root === expr.expanded) {
|
|
470
|
-
return [...this.graph.children(expr.expanded), this.graph.element(expr.expanded)]
|
|
471
|
-
}
|
|
472
|
-
return resolveElements.call(this, expr)
|
|
473
|
-
}
|
|
474
|
-
|
|
475
|
-
export function includeRelationExpr(this: ComputeCtx, expr: Expr.RelationExpr, where?: RelationPredicateFn) {
|
|
476
|
-
let sources, targets
|
|
477
|
-
if (Expr.isWildcard(expr.source) && !Expr.isWildcard(expr.target)) {
|
|
478
|
-
sources = resolveNeighbours.call(this, expr.target)
|
|
479
|
-
targets = resolveRelationExprElements.call(this, expr.target)
|
|
480
|
-
} else if (!Expr.isWildcard(expr.source) && Expr.isWildcard(expr.target)) {
|
|
481
|
-
sources = resolveRelationExprElements.call(this, expr.source)
|
|
482
|
-
targets = resolveNeighbours.call(this, expr.source)
|
|
483
|
-
} else {
|
|
484
|
-
sources = resolveRelationExprElements.call(this, expr.source)
|
|
485
|
-
targets = resolveRelationExprElements.call(this, expr.target)
|
|
486
|
-
}
|
|
487
|
-
const edges = this.graph.edgesBetween(sources, targets)
|
|
488
|
-
if (expr.isBidirectional === true) {
|
|
489
|
-
edges.push(...this.graph.edgesBetween(targets, sources))
|
|
490
|
-
}
|
|
491
|
-
this.addEdges(filterEdges(edges, where)).forEach(edge => {
|
|
492
|
-
this.activeGroup.addImplicit(edge.source, edge.target)
|
|
493
|
-
})
|
|
494
|
-
}
|
|
495
|
-
|
|
496
|
-
export function excludeRelationExpr(this: ComputeCtx, expr: Expr.RelationExpr, where?: RelationPredicateFn) {
|
|
497
|
-
const isSource = elementExprToPredicate(expr.source)
|
|
498
|
-
const isTarget = elementExprToPredicate(expr.target)
|
|
499
|
-
const satisfies = (edge: ComputeCtx.Edge) => {
|
|
500
|
-
let result = isSource(edge.source) && isTarget(edge.target)
|
|
501
|
-
if (!result && expr.isBidirectional) {
|
|
502
|
-
result = isSource(edge.target) && isTarget(edge.source)
|
|
503
|
-
}
|
|
504
|
-
return result
|
|
505
|
-
}
|
|
506
|
-
const edges = this.edges.filter(satisfies)
|
|
507
|
-
const relations = filterRelations(edges, where)
|
|
508
|
-
this.excludeRelation(...relations)
|
|
509
|
-
}
|
|
@@ -1,61 +0,0 @@
|
|
|
1
|
-
import type { DynamicViewRule, DynamicViewStep, Fqn, ViewID, ViewRulePredicate } from '@likec4/core'
|
|
2
|
-
import { partition } from 'remeda'
|
|
3
|
-
import { type FakeElementIds, fakeModel } from '../../compute-view/__test__/fixture'
|
|
4
|
-
import { computeDynamicView } from '../index'
|
|
5
|
-
|
|
6
|
-
const emptyView = {
|
|
7
|
-
__: 'dynamic' as const,
|
|
8
|
-
id: 'index' as ViewID,
|
|
9
|
-
title: null,
|
|
10
|
-
description: null,
|
|
11
|
-
tags: null,
|
|
12
|
-
links: null,
|
|
13
|
-
customColorDefinitions: {},
|
|
14
|
-
rules: []
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
type StepExpr = `${FakeElementIds} ${'->' | '<-'} ${FakeElementIds}`
|
|
18
|
-
type StepProps = Omit<DynamicViewStep, 'source' | 'target' | 'isBackward'>
|
|
19
|
-
|
|
20
|
-
export function $step(expr: StepExpr, props?: string | Partial<StepProps>): DynamicViewStep {
|
|
21
|
-
const title = typeof props === 'string' ? props : props?.title
|
|
22
|
-
if (expr.includes(' -> ')) {
|
|
23
|
-
const [source, target] = expr.split(' -> ')
|
|
24
|
-
return {
|
|
25
|
-
source: source as Fqn,
|
|
26
|
-
target: target as Fqn,
|
|
27
|
-
...(typeof props === 'object' ? props : {}),
|
|
28
|
-
title: title ?? null
|
|
29
|
-
}
|
|
30
|
-
}
|
|
31
|
-
if (expr.includes(' <- ')) {
|
|
32
|
-
const [target, source] = expr.split(' <- ')
|
|
33
|
-
return {
|
|
34
|
-
source: source as Fqn,
|
|
35
|
-
target: target as Fqn,
|
|
36
|
-
...(typeof props === 'object' ? props : {}),
|
|
37
|
-
title: title ?? null,
|
|
38
|
-
isBackward: true
|
|
39
|
-
}
|
|
40
|
-
}
|
|
41
|
-
throw new Error(`Invalid step expression: ${expr}`)
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
export function compute(stepsAndRules: (DynamicViewStep | ViewRulePredicate)[]) {
|
|
45
|
-
const [steps, rules] = partition(stepsAndRules, (s): s is DynamicViewStep => 'source' in s)
|
|
46
|
-
const result = computeDynamicView(
|
|
47
|
-
{
|
|
48
|
-
...emptyView,
|
|
49
|
-
steps,
|
|
50
|
-
rules: rules as DynamicViewRule[]
|
|
51
|
-
},
|
|
52
|
-
fakeModel
|
|
53
|
-
)
|
|
54
|
-
if (!result.isSuccess) {
|
|
55
|
-
throw result.error
|
|
56
|
-
}
|
|
57
|
-
return Object.assign(result.view, {
|
|
58
|
-
nodeIds: result.view.nodes.map((node) => node.id) as string[],
|
|
59
|
-
edgeIds: result.view.edges.map((edge) => edge.id) as string[]
|
|
60
|
-
})
|
|
61
|
-
}
|